Redis 提供了五种基本的数据结构(Key-Value 类型),并根据不同的使用场景和数据量大小,采用不同的底层数据结构进行优化。以下是 Redis 基本数据结构及其底层实现的详细说明:
一、5种基本数据结构及底层实现
1. 字符串(String)
-
底层实现:
简单动态字符串(SDS, Simple Dynamic String)- 特点:
- SDS 是 Redis 自定义的字符串结构,解决了 C 语言字符串的缺陷(如非二进制安全、无法高效获取长度等)。
- 每个 SDS 结构包含
len
(已使用长度)、free
(未使用长度)和buf[]
(存储实际数据的字节数组)。 - 支持动态扩容(如
len < 1MB
时扩容到2*len
,否则扩容len + 1MB
)。
- 示例结构:
struct sdshdr { int len; // 已使用长度 int free; // 未使用长度 char buf[]; // 实际存储的字节数组 }
- 特点:
-
应用场景:
- 缓存、计数器、分布式锁、存储小对象等。
2. 列表(List)
-
底层实现:
双向链表(Linked List) 或 压缩列表(Ziplist),根据数据量和配置动态切换:- Redis 3.2 之前:
- 小数据量(默认
list-max-ziplist-size
配置):使用 Ziplist。 - 大数据量:使用 双向链表(LinkedList)。
- 小数据量(默认
- Redis 3.2 之后:
- 统一使用 QuickList(双向链表 + Ziplist 的组合)。
- QuickList 将链表的每个节点替换为 Ziplist,减少内存碎片并提高性能。
- Redis 3.2 之前:
-
特点:
- 双向链表支持 O(1) 的头尾插入/删除操作。
- Ziplist 通过连续内存存储数据,节省内存但牺牲随机访问效率。
-
应用场景:
- 消息队列、日志记录、分页查询等。
3. 哈希(Hash)
-
底层实现:
字典(Dict, Hash Table) 或 压缩列表(Ziplist),根据数据量动态切换:- 小数据量(默认
hash-max-ziplist-entries=512
且hash-max-ziplist-value=64
):使用 Ziplist。 - 大数据量:使用 字典(Dict)。
- 小数据量(默认
-
特点:
- 字典基于哈希表实现,支持 O(1) 的增删改查。
- Ziplist 通过连续内存存储键值对,节省内存但限制了数据规模。
-
应用场景:
- 存储对象(如用户信息)、缓存配置、购物车等。
4. 集合(Set)
-
底层实现:
整数集合(Intset) 或 字典(Dict),根据数据类型动态切换:- 元素为整数且数量较小(默认
set-max-intset-entries=512
):使用 Intset。 - 其他情况:使用 字典(Dict)(键存储元素,值为空)。
- 元素为整数且数量较小(默认
-
特点:
- Intset 是一个有序的整数数组,支持类型升级(如从
int16_t
升级到int32_t
)。 - 字典通过哈希表实现去重和快速查找。
- Intset 是一个有序的整数数组,支持类型升级(如从
-
应用场景:
- 标签系统、好友关系、抽奖池等。
5. 有序集合(Sorted Set, ZSet)
-
底层实现:
跳跃表(Skip List) + 字典(Dict) 或 压缩列表(Ziplist),根据数据量动态切换:- 小数据量(默认
zset-max-ziplist-entries=128
且zset-max-ziplist-value=64
):使用 Ziplist。 - 大数据量:使用 跳跃表 + 字典。
- 跳跃表用于按分数排序(O(log N) 查找)。
- 字典用于快速定位元素(O(1) 查找)。
- 小数据量(默认
-
特点:
- 跳跃表通过多层链表实现高效排序和范围查询。
- Ziplist 通过连续内存存储元素和分数,节省内存。
-
应用场景:
- 排行榜、时间序列数据、优先队列等。
二、其他特殊数据结构(底层实现)
Redis 还利用以下底层数据结构支持更多高级功能:
-
位图(Bitmap):
- 底层基于字符串(SDS)实现,通过位操作(
SETBIT
,GETBIT
)存储布尔值。 - 应用场景:用户活跃统计、签到系统等。
- 底层基于字符串(SDS)实现,通过位操作(
-
HyperLogLog:
- 基于概率算法(LogLog 算法)估算基数(UV 统计),底层使用固定大小的数组(12KB)。
-
地理空间(Geo):
- 底层基于有序集合(ZSet)实现,通过
GEOADD
和GEORADIUS
存储和查询地理坐标。
- 底层基于有序集合(ZSet)实现,通过
-
流(Stream):
- 底层基于 Radix Tree 实现,支持高效的消息追加和消费组管理。
三、总结对比表
Redis 数据类型 | 底层实现(小数据量) | 底层实现(大数据量) | 特点 |
---|---|---|---|
String | SDS | SDS | 二进制安全,动态扩容 |
List | Ziplist | QuickList | 支持 O(1) 插入/删除 |
Hash | Ziplist | Dict | 键值对存储,内存高效 |
Set | Intset | Dict | 无序去重集合 |
ZSet | Ziplist | Skip List + Dict | 有序去重集合,支持范围查询 |
Bitmap | SDS | SDS | 位操作,节省内存 |
HyperLogLog | 固定数组 | 固定数组 | 基数估算,误差率低 |
Geo | ZSet | ZSet | 地理坐标存储与查询 |
四、设计原则
-
内存与性能的平衡:
- 小数据量时优先使用压缩列表(Ziplist)节省内存。
- 大数据量时切换到更高效的结构(如字典、跳跃表)。
-
渐进式 Rehash:
- 哈希表扩容时通过分阶段迁移数据(避免一次性耗时操作)。
-
编码转换:
- 根据数据特性动态切换底层结构(如 Hash 从小到大转换为字典)。
通过灵活的底层数据结构设计,Redis 在高性能和内存效率之间实现了良好的平衡,适用于多种业务场景。