Redis7 底层数据结构解析
Redis底层数据结构深度解析(基于Redis 7.2.5)
本文深入剖析Redis核心数据类型的底层实现机制,涵盖String、Hash、List、Set、Zset的实现原理及版本演进差异。
一、Redis数据存储核心机制
Redis所有数据以redisObject
结构统一封装:
typedef struct redisObject {unsigned type:4; // 数据类型(string, hash等)unsigned encoding:4; // 底层编码(int, embstr等)unsigned lru:LRU_BITS; // 缓存淘汰策略信息int refcount; // 引用计数void *ptr; // 指向实际数据的指针
} robj;
- 查看指令:
TYPE key
:返回数据类型OBJECT ENCODING key
:查看底层编码
二、String类型底层结构
三种编码方式:
- int编码
- 条件:值为整数字符串(可转为long)
- 特点:ptr直接存储整数值(省去指针开销)
- embstr编码
- 条件:字符串长度 ≤ 44字节
- 特点:内存连续分配,RedisObject与SDS共享内存
- raw编码
- 条件:字符串长度 > 44字节
- 特点:RedisObject与SDS分离存储
SDS(Simple Dynamic String)
动态字符串结构,解决C字符串缺陷:
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; // 已用长度uint8_t alloc; // 总空间unsigned char flags; // 类型标识char buf[]; // 数据存储
};
优势:
- O(1)复杂度获取长度
- 二进制安全(允许存储
\0
) - 预分配减少内存重分配
三、Hash类型底层结构
编码切换规则:
条件 | 编码方式 |
---|---|
所有键值对数量 ≤ hash-max-listpack-entries (默认512) 且 所有值长度 ≤ hash-max-listpack-value (默认64字节) | listpack |
任一条件不满足 | hashtable |
Listpack(替代Redis6的ziplist)
连续内存结构解决ziplist连锁更新问题:
字段 | 说明 |
---|---|
total-bytes (4B) | 总字节数 |
num-elements (2B) | 元素数量 |
entry (变长) | 数据节点(每个键值对) |
end-byte (1B) | 结束标识(0xFF) |
节点结构:
[编码类型][数据长度][实际数据]
→ 无需记录前驱节点长度,避免连锁更新
四、List类型底层结构
编码规则:
- listpack编码:元素少且长度小
- quicklist编码:元素多或长度大(默认切换阈值:
list-max-listpack-size = -2
即8KB)
Quicklist结构
双向链表 + Listpack的复合结构:
typedef struct quicklist {quicklistNode *head;quicklistNode *tail;unsigned long count; // 总元素数unsigned long len; // 节点数...
} quicklist;typedef struct quicklistNode {struct quicklistNode *prev;struct quicklistNode *next;unsigned char *entry; // 指向listpacksize_t sz; // listpack字节大小...
} quicklistNode;
优势:
- 链表结构:高效增删(O(1))
- Listpack节点:内存连续,减少碎片
五、Set类型底层结构
编码切换规则:
条件 | 编码方式 |
---|---|
元素全为整数 & 元素数量 ≤ set-max-intset-entries (默认512) | intset |
元素数量 ≤ set-max-listpack-entries (默认128) 且 所有元素长度 ≤ set-max-listpack-value (默认64字节) | listpack |
任一条件不满足 | hashtable |
Intset整数集合
typedef struct intset {uint32_t encoding; // 编码方式(int16/int32/int64)uint32_t length; // 元素数量int8_t contents[]; // 数据存储
} intset;
特点:元素有序存储,二分查找效率高
六、Zset类型底层结构
编码切换规则:
条件 | 编码方式 |
---|---|
元素数量 ≤ zset-max-listpack-entries (默认128) 且 所有值长度 ≤ zset-max-listpack-value (默认64字节) | listpack |
任一条件不满足 | skiplist |
Skiplist跳表
多层索引结构实现高效查找:
typedef struct zskiplistNode {sds ele; // 元素值double score; // 分值struct zskiplistNode *backward; // 后退指针struct zskiplistLevel {struct zskiplistNode *forward; // 前进指针unsigned long span; // 跨度} level[]; // 层级数组
} zskiplistNode;
性能:
- 查询/插入/删除:平均O(logN)
- 空间复杂度:O(N)
七、Redis版本数据结构对比
数据类型 | Redis 6 | Redis 7 |
---|---|---|
string | SDS | SDS |
hash | ziplist + hashtable | listpack + hashtable |
list | quicklist + ziplist | quicklist + listpack |
set | intset + hashtable | intset + listpack + hashtable |
zset | ziplist + skiplist | listpack + skiplist |
关键演进:Redis 7使用listpack全面替代ziplist,彻底解决连锁更新问题。
附:Redis高性能核心要素
- 精细化数据结构:针对场景选择最优编码
- 内存连续存储:SDS/listpack利用CPU缓存
- 惰性删除:异步释放避免阻塞
- 单线程模型:无锁操作减少竞争
- IO多路复用:epoll/kqueue高效网络处理