## Redis 底层数据类型### 简介Redis 作为一个高性能的键值存储系统,其高效性离不开底层数据结构的精心设计。理解 Redis 的底层数据结构不仅有助于我们更好地使用 Redis,还能帮助我们设计出更高效的缓存方案。### Redis 支持的数据结构Redis 并不是简单地使用字符串作为底层数据结构,它支持多种数据结构,包括:1.
字符串 (SDS)
2.
链表 (linked list)
3.
字典 (dict)
4.
跳跃表 (skiplist)
5.
整数集合 (intset)
6.
压缩列表 (ziplist)
7.
快速列表 (quicklist)
### 数据结构详解#### 1. 简单动态字符串 (SDS)Redis 没有直接使用 C 语言传统的字符串表示(以空字符'\0'结尾的字符数组),而是自己构建了一种名为简单动态字符串(Simple Dynamic String, SDS)的抽象类型。
SDS 的结构定义:
```c struct sdshdr {// 记录 buf 数组中已使用字节的数量// 等于 SDS 保存字符串的长度int len;// 记录 buf 数组中未使用字节的数量int free;// 字节数组,用于保存字符串char buf[]; }; ```
SDS 相比于 C 字符串的优势:
常数复杂度获取字符串长度:
SDS 中的 len 属性可以直接获取字符串长度,而 C 字符串需要 O(n) 的时间复杂度。
杜绝缓冲区溢出:
SDS 会在修改字符串时检查空间是否足够,避免了缓冲区溢出的问题。
减少修改字符串带来的内存重分配次数:
SDS 采用了空间预分配和惰性空间释放两种优化策略,减少了内存重分配的次数。
二进制安全:
SDS 中的 buf 数组可以存储任意二进制数据,而 C 字符串只能存储以空字符结尾的字符串。#### 2. 链表 (linked list)Redis 的链表实现是一个双端无环链表,每个节点都包含指向前一个节点和后一个节点的指针。
链表的结构定义:
```c typedef struct listNode {// 前置节点struct listNode
prev;// 后置节点struct listNode
next;// 节点的值void
value; } listNode; ```
Redis 使用链表实现的功能:
发布与订阅
慢查询
监视器#### 3. 字典 (dict)Redis 的字典使用哈希表作为底层实现,每个键值对都存储在哈希表的一个节点中。当发生哈希冲突时,Redis 使用链地址法来解决。
字典的结构定义:
```c typedef struct dictht {// 哈希表数组dictEntry
table;// 哈希表大小unsigned long size;// 哈希表大小掩码,用于计算索引值unsigned long sizemask;// 已有节点数量unsigned long used; } dictht;typedef struct dictEntry {// 键void
key;// 值union {void
val;uint64_t u64;int64_t s64;} v;// 指向下个哈希表节点,形成链表struct dictEntry
next; } dictEntry; ```
Redis 使用字典实现的功能:
数据库
哈希类型#### 4. 跳跃表 (skiplist)跳跃表是一种有序的数据结构,它通过在链表的基础上增加多级索引来实现快速查找。
跳跃表的结构:
每个节点包含多个指针,指向不同级别的下一个节点。节点的级别越高,跳过的节点就越多,查找速度也就越快。
Redis 使用跳跃表实现的功能:
有序集合类型#### 5. 整数集合 (intset)整数集合用于存储整数值,它可以根据存储的整数范围自动选择不同的数据结构进行存储,以节省内存空间。
整数集合的编码方式:
INTSET_ENC_INT16:
存储范围在 -32,768 到 32,767 之间的整数,每个整数占用 2 个字节。
INTSET_ENC_INT32:
存储范围在 -2,147,483,648 到 2,147,483,647 之间的整数,每个整数占用 4 个字节。
INTSET_ENC_INT64:
存储范围在 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 之间的整数,每个整数占用 8 个字节。
Redis 使用整数集合实现的功能:
集合类型的一部分#### 6. 压缩列表 (ziplist)压缩列表是一种为了节约内存而设计的顺序型数据结构,它将所有元素紧凑地存储在一块连续的内存区域中。
压缩列表的特点:
节省内存空间。
数据量较小时性能较高。
数据量较大时性能较低。
Redis 使用压缩列表实现的功能:
列表类型的一部分
哈希类型的一部分
有序集合类型的一部分#### 7. 快速列表 (quicklist)快速列表是 Redis 为了改进 ziplist 在数据量较大时的性能而设计的数据结构。它将多个 ziplist 连接起来,并使用双向链表维护它们的顺序。
快速列表的特点:
结合了 ziplist 和双向链表的优点。
数据量较大时性能优于 ziplist。
Redis 使用快速列表实现的功能:
列表类型### 总结Redis 通过使用多种底层数据结构来实现不同的数据类型,并根据不同的场景选择最优的数据结构来保证性能。理解 Redis 的底层数据结构可以帮助我们更好地使用 Redis,并设计出更高效的缓存方案。
Redis 底层数据类型
简介Redis 作为一个高性能的键值存储系统,其高效性离不开底层数据结构的精心设计。理解 Redis 的底层数据结构不仅有助于我们更好地使用 Redis,还能帮助我们设计出更高效的缓存方案。
Redis 支持的数据结构Redis 并不是简单地使用字符串作为底层数据结构,它支持多种数据结构,包括:1. **字符串 (SDS)** 2. **链表 (linked list)** 3. **字典 (dict)** 4. **跳跃表 (skiplist)** 5. **整数集合 (intset)** 6. **压缩列表 (ziplist)** 7. **快速列表 (quicklist)**
数据结构详解
1. 简单动态字符串 (SDS)Redis 没有直接使用 C 语言传统的字符串表示(以空字符'\0'结尾的字符数组),而是自己构建了一种名为简单动态字符串(Simple Dynamic String, SDS)的抽象类型。**SDS 的结构定义:**```c struct sdshdr {// 记录 buf 数组中已使用字节的数量// 等于 SDS 保存字符串的长度int len;// 记录 buf 数组中未使用字节的数量int free;// 字节数组,用于保存字符串char buf[]; }; ```**SDS 相比于 C 字符串的优势:*** **常数复杂度获取字符串长度:**SDS 中的 len 属性可以直接获取字符串长度,而 C 字符串需要 O(n) 的时间复杂度。 * **杜绝缓冲区溢出:**SDS 会在修改字符串时检查空间是否足够,避免了缓冲区溢出的问题。 * **减少修改字符串带来的内存重分配次数:**SDS 采用了空间预分配和惰性空间释放两种优化策略,减少了内存重分配的次数。 * **二进制安全:**SDS 中的 buf 数组可以存储任意二进制数据,而 C 字符串只能存储以空字符结尾的字符串。
2. 链表 (linked list)Redis 的链表实现是一个双端无环链表,每个节点都包含指向前一个节点和后一个节点的指针。**链表的结构定义:**```c typedef struct listNode {// 前置节点struct listNode *prev;// 后置节点struct listNode *next;// 节点的值void *value; } listNode; ```**Redis 使用链表实现的功能:*** 发布与订阅 * 慢查询 * 监视器
3. 字典 (dict)Redis 的字典使用哈希表作为底层实现,每个键值对都存储在哈希表的一个节点中。当发生哈希冲突时,Redis 使用链地址法来解决。**字典的结构定义:**```c typedef struct dictht {// 哈希表数组dictEntry **table;// 哈希表大小unsigned long size;// 哈希表大小掩码,用于计算索引值unsigned long sizemask;// 已有节点数量unsigned long used; } dictht;typedef struct dictEntry {// 键void *key;// 值union {void *val;uint64_t u64;int64_t s64;} v;// 指向下个哈希表节点,形成链表struct dictEntry *next; } dictEntry; ```**Redis 使用字典实现的功能:*** 数据库 * 哈希类型
4. 跳跃表 (skiplist)跳跃表是一种有序的数据结构,它通过在链表的基础上增加多级索引来实现快速查找。**跳跃表的结构:**每个节点包含多个指针,指向不同级别的下一个节点。节点的级别越高,跳过的节点就越多,查找速度也就越快。**Redis 使用跳跃表实现的功能:*** 有序集合类型
5. 整数集合 (intset)整数集合用于存储整数值,它可以根据存储的整数范围自动选择不同的数据结构进行存储,以节省内存空间。**整数集合的编码方式:*** **INTSET_ENC_INT16:** 存储范围在 -32,768 到 32,767 之间的整数,每个整数占用 2 个字节。 * **INTSET_ENC_INT32:** 存储范围在 -2,147,483,648 到 2,147,483,647 之间的整数,每个整数占用 4 个字节。 * **INTSET_ENC_INT64:** 存储范围在 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 之间的整数,每个整数占用 8 个字节。**Redis 使用整数集合实现的功能:*** 集合类型的一部分
6. 压缩列表 (ziplist)压缩列表是一种为了节约内存而设计的顺序型数据结构,它将所有元素紧凑地存储在一块连续的内存区域中。**压缩列表的特点:*** 节省内存空间。 * 数据量较小时性能较高。 * 数据量较大时性能较低。**Redis 使用压缩列表实现的功能:*** 列表类型的一部分 * 哈希类型的一部分 * 有序集合类型的一部分
7. 快速列表 (quicklist)快速列表是 Redis 为了改进 ziplist 在数据量较大时的性能而设计的数据结构。它将多个 ziplist 连接起来,并使用双向链表维护它们的顺序。**快速列表的特点:*** 结合了 ziplist 和双向链表的优点。 * 数据量较大时性能优于 ziplist。**Redis 使用快速列表实现的功能:*** 列表类型
总结Redis 通过使用多种底层数据结构来实现不同的数据类型,并根据不同的场景选择最优的数据结构来保证性能。理解 Redis 的底层数据结构可以帮助我们更好地使用 Redis,并设计出更高效的缓存方案。