Redis中的String编码转换底层原理及6.0新特性

String编码转换底层原理

String对象为什么把大于39字节或者44字节的字符串编码为raw,小于的时候编码为embstr?

在Redis3.2以前的版本中,SDS作为字符串类型中存储字符串内容的结构,源码如下:

3.2版本SDS结构

struct sdshdr {// 记录buf数组中已使用字节的数量// 等于SDS保存字符串的长度 4byteint len;// 记录buf数组中未使用字节的数量 4byteint free;// 字节数组,用于保存字符串 字节\0结尾的字符串占用了1bytechar buf[];
}

Redis对象头

一个字符串对象不仅仅包含SDS结构,还包含了RedisObject(Redis对象头),这时每个Redis对象都要携带的一种结构跟Java对象类似,Java对象也有相应的对象头,它的结构如下

// Redis对象
typedef struct redisObject {// 类型 4bits; 即【String、List、Hash、Set、Zset】中的一个unsigned type:4// 编码方式 4 bits, encoding表示对象底层所使用的编码unsigned encoding:4;// LRU时间(相对于server.lrulock) 24bits;unsigned lru:24;// 引用计数 Redis里面的数据可以通过引用计数进行共享 32bitsint refcount;// 指向对象的值 64bitvoid* ptr;
} robj; // 16bytes

操作系统中的内存分配

由于操作系统使用jmalloc和tmalloc进行内存的分配,而内存分配的单位都是2的N次方,所以是2,4,8,16,32,64,如果Redis采取32字节分配的化,那么32-16(RedisObject)-9(3.2版本的SDS)=7,相当于可使用字节数为7字节,Redis认为太过于小了,所以Redis采取分配的是64字节,即64-25=39。

SDS结构优化

在Redis之后的版本中,为了进一步优化字符串对象在一次操作系统的内存分配中扩大可使用的空间,又将sdshdr分为了sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64结构如下

struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used */uint8_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
// 一些变量的定义 
#define SDS_TYPE_5  0
#define SDS_TYPE_8  1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

结构示例图

  • sdshdr5的结构如图
    在这里插入图片描述
  • sdshdr8的结构如图
    在这里插入图片描述

疑惑解答

有人可能会问既然分出来这么多的结构,如果用sdshdr5的结构,那么64-16-1-1=46个字节,跟平常说的44个字节不一样,如果我们用sdshdr5的结构,那么这个结构的flags中只有5个bit可以让我们使用,
表示的空间地址就是2^5=32个长度,表示的空间太小了,所以我们得用sdshdr8的结构那么可以表示的空间地址
将会是2^8=256,但实际上,在Redis内部中,键是使用sdshdr5的结构,因为键不大可能会更新,而值会经常更新,所以干脆直接sdshdr8来表示值对象

Redis6.0新特性

多线程

概述

redis6.0提供了多线程的支持,redis6以前的版本,严格来说也是多线程,只不过执行用户命令的请求是单线程模型,还有一些线程用来执行后台任务,比如unlink删除大key,rdb持久化等

redis6.0提供了多线程的读写IO,但是最终执行用户命令的线程依然是单线程的,这样,就没有多线程数据的竞争关系,依然很高效

线程模型

在这里插入图片描述

  • redis6.0以前线程执行模式,如下操作再一个线程中执行完成

在这里插入图片描述

  • redis6.0线程执行模式:
参数配置

可以通过如下参数配置多线程模型:

io-threads 4 // 这里说 有三个IO线程,还有一个线程是main线程,main线程负责IO读写和命令执行操作

默认情况下,如上配置,有三个IO线程,这三个IO线程只会执行IO中的write操作,也就是说,read和命令执行都由main线程执行,最后多线程讲数据写回客户端。

在这里插入图片描述
开启了如下参数:

io-threadas-do-reads yes // 将支持IO线程执行 读写任务

Client side caching(客户端缓存)

概述

redis6提供了服务端追踪key的变化,客户端缓存数据的特性,这需要客户端实现
在这里插入图片描述

执行流程

当客户端访问某个key时,服务端将记录key和client,客户端拿到数据后,进行客户端缓存,这时,当key再次被访问时,key将被直接返回,避免了与redis服务器的再次交互,节省服务端资源,当数据被其他请求修改时,服务端将主动通知客户端失效的key,客户端进行本地失效,下次请求时,重新获取最新数据目前只有lettuce对其进行了支持:

代码示例
  • 依赖导入
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce‐core</artifactId>
<version>6.0.0.RELEASE</version>
</dependency>
  • Java代码
public class Main {public static void main(String[] args) {RedisClient redisClient = RedisClient.create("redis://127.0.0.1");Map<String, String> clientCache = new ConcurrentHashMap<>();StatefulRedisConnection<String, String> myself = redisClient.connect();CacheFrontend<String, String> frontend = ClientSideCaching.enable(CacheAccessor.forMap(clientCache), myself,TrackingArgs.Builder.enabled().noloop));String key = "csk";int count = 0;while (true) {System.out.println(frontend.get(key));TimeUnit.SECONDS.sleep(3);if (count++ == Integer.MAX_VALUE) {myself.close();redisClient.shutdown();}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/549205.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Unity每日一记】unity中的内置宏和条件编译(Unity内置脚本符号)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

项目性能优化—使用JMeter压测SpringBoot项目

我们的压力测试架构图如下&#xff1a; 配置JMeter 在JMeter的bin目录&#xff0c;双击jmeter.bat 新建一个测试计划&#xff0c;并右键添加线程组&#xff1a; 进行配置 一共会发生4万次请求。 ctrl s保存&#xff1b; 添加http请求&#xff1a; 配置http请求&#xff1a;…

openEuler-22.03-LTS-SP2更改阿里云yum安装源

openEuler-22.03-LTS-SP2更改阿里云yum安装源 将文件/etc/yum.repos.d/openEuler.repo&#xff0c;替换为以下内容 [OS] nameOS baseurlhttps://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP2/OS/$basearch/ enabled1 gpgcheck1 gpgkeyhttps://mirrors.aliyun.com/op…

为 java 开发者设计的性能测试框架,用于压测+测试报告生成

拓展阅读 junit5 系列教程 基于 junit5 实现 junitperf 源码分析 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) Junit performance rely on junit5 and jdk8.(java 性能测试框架。压测测试报告生成。) junitperf junitperf 是一款为 java 开…

蓝桥杯练习02随机数生成器

随机数生成器 介绍 实际工作中随机数的使用特别多&#xff0c;比如随机抽奖、随机翻牌。通过随机数还能实现很多有趣的效果&#xff0c;比如随机改变元素的位置或颜色。 本题需要在已提供的基础项目中使用JS知识封装一个函数&#xff0c;该函数可以根据需要&#xff0c;生成指…

排序问题—java实现

冒泡排序 算法思想&#xff1a; 每次比较相邻元素&#xff0c;若逆序则交换位置&#xff0c;每一趟比较n-1次&#xff0c;确定一个最大值。故需比较n趟&#xff0c;来确定n个数的位置。 外循环来表示比较的趟数&#xff0c;每一趟确定一个最大数的位置内循环来表示相邻数字两…

服务器病毒木马通用排查处理应急响应流程

目录 一、勒索病毒发作的特征 二、勒索病毒的应急响应 三、勒索病毒预防与事后加固 一、勒索病毒发作的特征 如果发现大量统一后缀的文件&#xff1b;发现勒索信在Linux/home、/usr等目录&#xff0c;在Windows 桌面或者是被加密文件的文件夹下。如果存在以上特…

mybatis-plus 的saveBatch性能分析

Mybatis-Plus 的批量保存saveBatch 性能分析 目录 Mybatis-Plus 的批量保存saveBatch 性能分析背景批量保存的使用方案循环插入使用PreparedStatement 预编译优点&#xff1a;缺点&#xff1a; Mybatis-Plus 的saveBatchMybatis-Plus实现真正的批量插入自定义sql注入器定义通用…

Linux进程通信补充——System V通信

三、System V进程通信 ​ System V是一个单独设计的内核模块&#xff1b; ​ 这套标准的设计不符合Linux下一切皆文件的思想&#xff0c;尽管隶属于文件部分&#xff0c;但是已经是一个独立的模块&#xff0c;并且shmid与文件描述符之间的兼容性做的并不好&#xff0c;网络通…

华为汽车业务迎关键节点,长安深蓝加入HI模式,车BU预计今年扭亏

‍编辑 |HiEV 一年之前&#xff0c;同样是在电动汽车百人会的论坛上&#xff0c;余承东在外界对于华为和AITO的质疑声中&#xff0c;第一次公开阐释了华为选择走智选车模式的逻辑。 一年之后&#xff0c;伴随问界M7改款、问界M9上市&#xff0c;华为智选车模式的面貌已经发生了…

使用jenkins-pipeline进行利用项目文件自动化部署到k8s上

Discard old builds:丢弃旧的构建,目的是管理存储空间、提升性能以及保持环境整洁 Do not allow concurrent builds: 禁止并发构建是指同一时间内只允许一个构建任务执行,避免多个构建同时运行可能带来的问题 Do not allow the pipeline to resume if the controller resta…

信息系统项目管理师018:计算机网络(2信息技术发展—2.1信息技术及其发展—2.1.2计算机网络)

文章目录 2.1.2 计算机网络1.网络标准协议2.软件定义网络3.第五代移动通信技术 记忆要点总结 2.1.2 计算机网络 在计算机领域中&#xff0c;网络就是用物理链路将各个孤立的工作站或主机相连在一起&#xff0c;组成数据链路&#xff0c;从而达到资源共享和通信的目的。凡将地理…