SDS
①获取字符串长度的时间复杂度为O(1) ②支持动态扩容 ③减少内存分配次数 ④二进制安全
当新增内容时 如果新字符串小于 1M , 则新空间为扩展后字符串长度的两倍 +1 ; 如果新字符串大于 1M , 则新空间为扩展后字符串长度 +1M+1 。 称为内存预分配。
IntSet
如果新增加的元素范围超过了当前编码范围,intset会自动升级编码方式。并将每个元素从后向前拷贝到正确的位置。元素是按照大小顺序存放,查找时使用二分查找进行查询。插入时为保持顺序,需要移动元素。
ziplist:
markdown
- 所有键值对的键和值长度都 < 64 字节
- 键值对数量 < 512 个
- 配置参数:`hash-max-ziplist-entries`、`hash-max-ziplist-value`
entry



Dict(字典)
diff
- 不满足 ziplist 条件时使用
- 使用链地址法解决冲突,插入时使用头插法,避免需要遍历到链表的尾部才能插入。
- 渐进式rehash策略



Dict扩容
loadFactor=used/size。 当负载因子loadFactor>=1,并且没有bgSave,bgReWrite等后台进程在运行时会进行扩容。

Dict收缩
当负载因子<0.1时,会进行收缩。

rehash

QuickList






SkipList



RedisObject

Redis的五种数据类型的编码方式

Redis 五种基本数据类型的底层实现
Redis 的五种基本数据类型(String、List、Hash、Set、Sorted Set)在不同的使用场景下会采用不同的底层数据结构实现,这种灵活的设计使得 Redis 能够在内存使用和性能之间取得良好平衡。
1. String(字符串)
底层实现:
- int:当存储的是整数值且可以用 long 类型表示时
- embstr:当字符串长度 ≤ 44 字节时(Redis 5.0+)
- raw:当字符串长度 > 44 字节时
- SDS (Simple Dynamic String):所有字符串类型的底层基础结构
SDS 结构特点:
c
struct sdshdr {
int len; // 已使用的长度
int free; // 未使用的空间
char buf[]; // 实际存储的字符数组
};
优点:O(1)时间复杂度获取长度、二进制安全、减少内存重分配次数
2. List(列表)
底层实现:
-
ziplist(压缩列表):
- 所有元素长度 < 64 字节
- 元素数量 < 512 个
- 配置参数:
list-max-ziplist-size
、list-compress-depth
-
linkedlist(双向链表):
- 不满足 ziplist 条件时使用
- 每个节点都是独立的字符串对象 在redis3.2之前使用zipList和linkedList,3.2后使用quickList
-
quicklist(快速列表,Redis 3.2+):
- ziplist 和 linkedlist 的混合体
- 默认实现方式,由多个 ziplist 节点组成的双向链表
- 配置参数:
list-max-ziplist-size
(每个ziplist节点大小)
3. Hash(哈希表)
底层实现:
-
ziplist:
- 所有键值对的键和值长度都 < 64 字节
- 键值对数量 < 512 个
- 配置参数:
hash-max-ziplist-entries
、hash-max-ziplist-value
-
hashtable(字典):
- 不满足 ziplist 条件时使用
- 使用链地址法解决冲突
- 渐进式rehash策略
字典结构:
c
typedef struct dict {
dictType *type; // 类型特定函数
void *privdata; // 私有数据
dictht ht[2]; // 哈希表数组(用于rehash)
long rehashidx; // rehash索引
} dict;
4. Set(集合)
底层实现:
- intset(整数集合) :
- 所有元素都是整数
- 元素数量 < 512 个
- 配置参数:
set-max-intset-entries
- hashtable :
- 不满足 intset 条件时使用
- 只有键没有值(值设为NULL)
intset 结构:
c
typedef struct intset {
uint32_t encoding; // 编码方式(int16/int32/int64)
uint32_t length; // 元素数量
int8_t contents[]; // 元素数组
} intset;
5. Sorted Set(有序集合)
底层实现:
- ziplist :
- 元素数量 < 128 个
- 所有成员长度 < 64 字节
- 配置参数:
zset-max-ziplist-entries
、zset-max-ziplist-value
- skiplist + hashtable :
- 不满足 ziplist 条件时使用
- 跳跃表用于排序和范围操作
- 哈希表用于O(1)复杂度的成员查找
跳跃表结构:
c
typedef struct zskiplistNode {
robj *obj; // 成员对象
double score; // 分值
struct zskiplistNode *backward; // 后退指针
struct zskiplistLevel {
struct zskiplistNode *forward; // 前进指针
unsigned int span; // 跨度
} level[]; // 层
} zskiplistNode;
底层数据结构转换机制
Redis 会根据配置参数自动在这些底层实现之间转换:
- 当元素数量或大小超过阈值时,从小内存结构转为大内存结构
- 转换是单向的,不会自动转回去
- 可以通过修改配置参数调整转换阈值
为什么采用多种底层实现?
- 内存效率:对小数据使用紧凑存储(如ziplist)
- 性能优化:对不同操作提供最优时间复杂度
- 灵活性:根据数据特征自动选择最佳结构
- 平衡性:在内存使用和CPU效率之间取得平衡
理解这些底层实现有助于合理配置Redis参数,优化内存使用和性能表现。