【Redis】SDS 简单动态字符串

时间:2023-02-26 17:53:36

Redis没有直接复用C语言的字符串,而是新建了SDS,作为String类型的一种存储结构。

在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)

【Redis】SDS 简单动态字符串

内部为当前字符串实际的分配的空间capacity一般要高于实际字符串长度len。当字符串长度1M时,扩容都是加倍现有空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度512M。


???? Redis为什么要重新设计一个SDS数据结构?

【Redis】SDS 简单动态字符串

???? SDS源码解析:

【Redis】SDS 简单动态字符串

在Redis源码sds.h中定义了SDS的结构,SDS中包含了以下属性:

  • len:字符串长度
  • alloc:分配的空间长度
  • flags:SDS类型
  • buf[]:字节数组

???? Redis 执行了set k1 v1,底层发生了什么?

【Redis】SDS 简单动态字符串

???? String类型的三大物理编码方式:int,embstr,raw

Redis底层会根据用户的不同键值使用不同的编码格式,自适应的选择较优的内部编码格式,而这一切对于用户完全透明。

【Redis】SDS 简单动态字符串

【Redis】SDS 简单动态字符串

【Redis】SDS 简单动态字符串

  • int 编码格式:

【Redis】SDS 简单动态字符串

Redis启动时会预先建立10000个分别存储0~9999的redisobject变量作为共享对象,这就意味着如果set字符串的键值在0~10000之间的话,则可以直接指向共享对象而不需要再建立新对象,此时键值不占空间。

【Redis】SDS 简单动态字符串

在Redis源代码,server.h:

【Redis】SDS 简单动态字符串

Redis6 Stirng类型的数据共享机制:

【Redis】SDS 简单动态字符串

Redis7 String类型数据共享机制:

【Redis】SDS 简单动态字符串

  • embstr 编码格式:

判断字符串长度,如果字符串长度小于44字节,就会创建一个embstr字符串:

【Redis】SDS 简单动态字符串

【Redis】SDS 简单动态字符串

【Redis】SDS 简单动态字符串

Redis 对于小于44字节的字符串采用的是​​OBJ_ENCODING_EMBSTR​​方式,EMBSTR嵌入式字符串。从内存结构上来说,字符串SDS结构体与其对应的redisObject对象分配在同一块连续的内存空间,类似于字符串SDS嵌入到redisObject对象之中一样。

  • raw 编码格式:

【Redis】SDS 简单动态字符串

当字符串的键值为长度大于44的超长字符串时,Redis则会将键值的内部编码方式改为​​OBJ_ENCODING_RAW​​格式,这与​​OBJ_ENCODING_EMBSTR​​编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续了。

【Redis】SDS 简单动态字符串

明明字符串长度没有超过44字节,为什么底层数据结构还是转换为了raw?

对于embstr,由于其实现是只读的,因此在对embstr对象进行修改时,会先转化为raw再进行修改。因此,只要是修改embstr对象,修改后的对象一定是raw的,无论是否达到了44个字节。