今天我们来聊一聊Redis里面的一个基础数据结构,字符串。在Redis中,字符串又叫做SDS,全称为Simple Dynamic String,翻译成中文就是简单的动态字符串。我们来看看到底有多么的简单!
struct SDS<T> {
T capacity; // 数组的容量
T len; // 数组的长度
byte flags; // 特殊标识位
byte[] content; // 具体的字符串内容
}
为什么这里要使用的是泛型T而不是直接使用int类型呢?作为节省内存到极致的Redis,对于长度较小的数据,能用short或者byte进行表示,不得不说,Redis真是斤斤计较!对于使用者来说,Redis可能只是缓存几千几万个key,但对于Redis来说,可能要缓存多个业务几百万个数据,所以积少成多,还是非常有价值的。
我们知道,在C语言中,是没有维护字符串数组的长度的,为什么Redis需要维护这个字符串的长度呢?我们不烦想一个现实的问题,在C语言中,类似'\0'的字符,系统函数读取到就认为是结束,所以像"abc'\0'dfg"这样的字符串,在C语言的系统函数只能读取到abc,如果我们不记录数组的长度,就有可能读取到被截断的数据。所以,Redis的字符串设计,让Redis的字符串是二进制安全的。除此之外,还避免了一些内存覆盖的问题,每次修改字符串也不一定需要重新申请空间,而且O(1)级别地求出字符串的长度。
我们再来讨论一个有意思的事情,在Redis中,字符串竟然有两种不同的存储形式,一个是embstr一个是raw结构。这两者有什么不同呢?
在Redis中,每一个数据结构,都有一个头部RedisObject,type是数据的类型,同一种类型有不同的存储格式,例如字符串可能是emb也可能是raw,lru用来存储内存淘汰的信息,refcount用来存引用计数的。而ptr用来指向SDS存储的地址。struct RedisObject {
int4 type; // 0.5字节
int4 encoding; // 0.5字节
int24 lru; // 3字节
int32 refcount; // 4字节
void *ptr; // 8字节(如果是64位系统)
} robj;
总共16个字节,而前面的SDS,用来表示长度、容量、标识符总共为3字节,总共19字节,加上每个结构最后字节用来表示'\0'的特殊表示,总共20字节。为了减少内存碎片,redis每次都会向操作系统申请32/64/128等2的n次幂的内存空间,一64字节为分界线,Redis小于64-20=44个字节的字符串,就会使用emb存储,否则就会使用raw进行存储。
为什么Redis要这么折腾呢?为什么不全部按照raw的格式进行存储呢?这里留一道课后题给大家进行思考!欢迎大家关注我,近期还准备了一些AI相关的知识,整理后会和大家继续分享。大家的支持是我继续唠嗑的动力。同名公众号(沙茶敏碎碎念)
(此处已添加圈子卡片,请到今日头条客户端查看)留言与评论(共有 0 条评论) |