Redis String底层数据结构

813 阅读2分钟

参考链接: www.jianshu.com/p/160fb0f73… 如想看源码就看上面的链接就好~~~~~~~~~~~~~~~~~~~

1 Redis底层存储是一个hash结构,与HashMap差不多,都是一个数据+链表组成的,然后拉链法解决冲突

6302559-30b668ac18b6a226.webp

2 其hash节点含key、value、next指针,如下

/*
* 哈希表节点
*/
typedef struct dictEntry {
// 键
void *key;
// 值
union {
    void *val;
    uint64_t u64;
    int64_t s64;
} v;
// 指向下个哈希表节点,形成链表
struct dictEntry *next;
} dictEntry;

3  redisObject是redis server存储最原子数据的数据结构

其中的void *ptr会指向真正的存储数据结构,我们set key value中的key和value其实由ptr指向真正保存的位置

typedef struct redisObject {
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    // 引用计数
    int refcount;
    // 指向实际值的指针
    void *ptr;
} robj;

4 Redis内部的String的数据结构 !!重点!!

其存储转化优先级如下:
1 如果存储的字符串长度 < 21 并可转为整数,则用整数存储
2 如果存储长度 <= 44(REDIS_ENCODING_EMBSTR_SIZE_LIMIT,网上阈值为39有问题,我测试过44这个阈值在Redis 4.0.0中才会转换)会转为embstr
3 其他情况都用SDS结构存储(也就是下面的raw)

image.png

4.1 embstr与raw比较

embstr的创建只需分配一次内存,而raw为两次(一次为sds分配对象,另一次为redisObject分配对象,embstr省去了第一次)。相对地,释放内存的次数也由两次变为一次。
embstr的redisObject和sds放在一起,更好地利用缓存带来的优势
缺点:redis并未提供任何修改embstr的方式,即embstr是只读的形式。对embstr的修改实际上是先转换为raw再进行修改。

4.2 sds存储的数据结构

/*
* 保存字符串对象的结构
*/struct sdshdr {
// buf 中已占用空间的长度
int len;
// buf 中剩余可用空间的长度
int free;
// 数据空间
char buf[];
};

可见其由len、free、buf组成。其他知识点:

1 sds创建的过程
-- 分配内存并初始化len和free字段

2 sds内存扩容(空间预分配)
-- 当字符串长度小于SDS_MAX_PREALLOC (1024*1024),那么就以2倍的速度扩容,当字符串长度大于SDS_MAX_PREALLOC,那么就以+SDS_MAX_PREALLOC的速度扩容。
-- 上面意思就是 <= 1MB 就是每次扩容都2倍扩容,> 1MB 时就每次扩容 +1MB 的大小

3 sds内存缩容(惰性空间释放)
-- 释放内存的过程中修改len和free字段,并不释放实际占用内存。会将结束符放到最前面(相当于惰性地删除 buf中的内容),并把这部分buf释放的长度加到free中

注意点图如下

image.png