Redis没有直接复用C语言的字符串,而是新建了SDS,作为String类型的一种存储结构。
在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)
内部为当前字符串实际的分配的空间capacity一般要高于实际字符串长度len。当字符串长度1M时,扩容都是加倍现有空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度512M。
🔥 Redis为什么要重新设计一个SDS数据结构?
📌 SDS源码解析:
在Redis源码sds.h中定义了SDS的结构,SDS中包含了以下属性:
- len:字符串长度
- alloc:分配的空间长度
- flags:SDS类型
- buf[]:字节数组
🔥 Redis 执行了set k1 v1
,底层发生了什么?
🔥 String类型的三大物理编码方式:int,embstr,raw
Redis底层会根据用户的不同键值使用不同的编码格式,自适应的选择较优的内部编码格式,而这一切对于用户完全透明。
- int 编码格式:
Redis启动时会预先建立10000个分别存储0~9999的redisobject变量作为共享对象,这就意味着如果set字符串的键值在0~10000之间的话,则可以直接指向共享对象而不需要再建立新对象,此时键值不占空间。
在Redis源代码,server.h:
Redis6 Stirng类型的数据共享机制:
Redis7 String类型数据共享机制:
- embstr 编码格式:
判断字符串长度,如果字符串长度小于44字节,就会创建一个embstr字符串:
Redis 对于小于44字节的字符串采用的是OBJ_ENCODING_EMBSTR
方式,EMBSTR嵌入式字符串。从内存结构上来说,字符串SDS结构体与其对应的redisObject对象分配在同一块连续的内存空间,类似于字符串SDS嵌入到redisObject对象之中一样。
- raw 编码格式:
当字符串的键值为长度大于44的超长字符串时,Redis则会将键值的内部编码方式改为OBJ_ENCODING_RAW
格式,这与OBJ_ENCODING_EMBSTR
编码方式的不同之处在于,此时动态字符串sds的内存与其依赖的redisObject的内存不再连续了。
明明字符串长度没有超过44字节,为什么底层数据结构还是转换为了raw?
对于embstr,由于其实现是只读的,因此在对embstr对象进行修改时,会先转化为raw再进行修改。因此,只要是修改embstr对象,修改后的对象一定是raw的,无论是否达到了44个字节。