Redis 五种数据类型及底层数据结构详解

目录

  1. [Redis 数据类型概览](#Redis 数据类型概览)
  2. [String 类型及底层实现](#String 类型及底层实现)
    • 2.1 简单动态字符串(SDS)
  3. [Hash 类型及底层实现](#Hash 类型及底层实现)
    • 3.1 哈希表(Hash Table)
    • 3.2 压缩列表(Ziplist)
  4. [List 类型及底层实现](#List 类型及底层实现)
    • 4.1 双向链表(LinkedList)
    • 4.2 压缩列表(Ziplist)
  5. [Set 类型及底层实现](#Set 类型及底层实现)
    • 5.1 哈希表
    • 5.2 整数集合(Intset)
  6. [Sorted Set 类型及底层实现](#Sorted Set 类型及底层实现)
    • 6.1 跳表(SkipList)
    • 6.2 压缩列表(Ziplist)
  7. 总结

Redis 数据类型概览

Redis 提供的五种主要数据类型,每一种都有其特定的用途:

  • String:最基础的键值对形式,可以存储字符串、整数、浮点数。
  • Hash:适合存储对象,可以用字段-值的形式存储数据。
  • List:链表结构,支持从两端操作,非常适合实现队列或栈。
  • Set:无序的唯一集合,适合存储不重复的数据。
  • Sorted Set:有序的集合,每个元素都会关联一个分数,支持按分数排序。

这些类型的底层实现并不完全相同,Redis 会根据存储的元素数量和数据结构自动选择最合适的存储方式。

String 类型及底层实现

String 是 Redis 中最基础的数据类型,一个键对应一个值。String 类型的值可以是普通字符串、数字、二进制数据等。其主要应用场景包括:

  • 缓存字符串数据。
  • 作为计数器存储整数或浮点数。
  • 存储用户信息等简单数据。

2.1 简单动态字符串(SDS)

Redis 的 String 类型底层使用的是 SDS(Simple Dynamic String) 来实现。SDS 是 Redis 为了替代 C 语言中的 char 类型字符串而设计的一种动态字符串结构,具有更高的灵活性和安全性。

SDS 的主要特点:

  • 动态扩展:当字符串长度增加时,SDS 可以自动扩展其容量,避免频繁的内存分配。
  • 预分配空间:SDS 为了减少内存重分配的次数,会预留一部分额外空间,尤其是在增长字符串时。
  • 惰性空间释放:当缩短 SDS 字符串时,并不会立即释放多余的内存,而是保留这些空间,等待未来使用。
  • 二进制安全:SDS 可以存储任意二进制数据,而不仅仅是文本数据。

SDS 的结构如下:

c 复制代码
struct sdshdr {
    int len;         // 已使用的长度
    int free;        // 剩余的可用空间
    char buf[];      // 实际保存字符串的地方
};

这种结构设计使得 SDS 在处理字符串时具备高效性和灵活性。

Hash 类型及底层实现

Hash 类型在 Redis 中用于存储对象数据,类似于传统编程语言中的字典或 Map 结构。每个键对应一个字段和字段值的集合,非常适合存储用户信息等对象数据。

3.1 哈希表(Hash Table)

当 Hash 类型的数据量较大时,Redis 使用经典的 哈希表(Hash Table) 来存储。哈希表通过计算键的哈希值将字段-值对映射到不同的桶中,从而实现快速的 O(1) 复杂度的查找、插入和删除操作。

Redis 使用的哈希表结构为 dict,其主要结构如下:

c 复制代码
typedef struct dict {
    dictEntry **table;   // 哈希桶数组
    unsigned long size;  // 哈希表的大小
    unsigned long sizemask;  // 用于计算索引的掩码
    unsigned long used;  // 已使用的哈希桶数量
} dict;

Redis 为了防止哈希冲突,使用了链地址法来解决,当多个键映射到同一个桶时,这些键值对会以链表的形式存储在该桶中。

3.2 压缩列表(Ziplist)

当 Hash 中的字段数量较少且每个字段和字段值都很小的时候,Redis 会使用更节省内存的 压缩列表(Ziplist) 结构来存储数据。

压缩列表是一种紧凑的双向链表,所有元素紧密排列在一起,不会为每个元素单独分配内存。这种结构极大地减少了内存的使用,但在数据量较大时,性能会有所下降。

List 类型及底层实现

List 是 Redis 中的链表结构,支持从两端进行高效的插入和删除操作,适合用于实现队列、栈等数据结构。List 常用于社交网络的消息流、任务队列等场景。

4.1 双向链表(LinkedList)

当 List 中存储的元素较多时,Redis 使用 双向链表(LinkedList) 结构来实现。双向链表允许我们在 O(1) 时间内从头部和尾部进行插入和删除操作。

Redis 使用的链表结构如下:

c 复制代码
typedef struct listNode {
    struct listNode *prev;  // 前一个节点
    struct listNode *next;  // 后一个节点
    void *value;            // 节点的值
} listNode;

typedef struct list {
    listNode *head;         // 头节点
    listNode *tail;         // 尾节点
} list;

双向链表的设计使得 List 操作非常高效,尤其是在实现先进先出的队列时。

4.2 压缩列表(Ziplist)

当 List 中的元素较少时,Redis 仍会选择使用 压缩列表(Ziplist) 以节省内存。与 Hash 的情况类似,Ziplist 在节省内存的同时也会牺牲一定的性能。

Set 类型及底层实现

Set 是无序的集合,集合中的元素是唯一的,且不允许重复。Set 非常适合存储不重复的数据,如标签系统、好友关系等。

5.1 哈希表

当 Set 中的元素数量较多时,Redis 使用 哈希表 来存储集合。由于 Set 不需要存储值,只需要确保元素的唯一性,哈希表在这里仅使用键来保证数据的唯一性。

5.2 整数集合(Intset)

当 Set 中存储的元素是整数且数量较少时,Redis 会使用 整数集合(Intset) 来存储。这是一种紧凑型的数据结构,专门用来存储小范围的整数集合。

整数集合的结构如下:

c 复制代码
typedef struct intset {
    uint32_t encoding;      // 编码方式
    uint32_t length;        // 集合中的元素个数
    int8_t contents[];      // 存储整数的数组
} intset;

整数集合根据元素大小自动选择不同的编码方式,以提高存储效率。

Sorted Set 类型及底层实现

Sorted Set 是 Redis 中的有序集合,集合中的每个元素都有一个分数,元素按照分数进行排序。Sorted Set 常用于排行榜系统、按权重排序的数据等场景。

6.1 跳表(SkipList)

当 Sorted Set 的元素较多时,Redis 使用 跳表(SkipList) 结构来实现。跳表是一种可以在 O(log N) 时间复杂度内进行插入、删除和查找的有序数据结构。

Redis 中的跳表结构如下:

c 复制代码
typedef struct zskiplist {
    struct zskiplistNode *header;  // 跳表头节点
    struct zskiplistNode *tail;    // 跳表尾节点




    unsigned long length;          // 跳表长度
    int level;                     // 跳表层数
} zskiplist;

跳表通过多层级链表来加快数据的查找速度,是一种内存友好的排序结构。

6.2 压缩列表(Ziplist)

当 Sorted Set 中的元素较少时,Redis 也可以使用 压缩列表(Ziplist) 来存储。这与 Hash 和 List 的实现类似,用以节省内存。

总结

Redis 提供了五种主要的数据类型,每种类型都有其特定的应用场景和底层数据结构。在实际使用中,选择合适的数据类型和理解其底层实现有助于优化 Redis 的性能。通过合理地设计和运用 Redis 的数据结构,我们可以在保证性能的前提下,最大化地利用 Redis 的优势。

相关推荐
huapiaoy1 分钟前
Redis中数据类型的使用(hash和list)
redis·算法·哈希算法
bug菌¹20 分钟前
滚雪球学Oracle[6.2讲]:Data Guard与灾难恢复
数据库·oracle·data·灾难恢复·guard
一般路过糸.23 分钟前
MySQL数据库——索引
数据库·mysql
武昌库里写JAVA40 分钟前
【Java】Java面试题笔试
c语言·开发语言·数据结构·算法·二维数组
Cengineering1 小时前
sqlalchemy 加速数据库操作
数据库
【D'accumulation】1 小时前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
Cikiss1 小时前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
Cikiss1 小时前
微服务实战——平台属性
java·数据库·后端·微服务
小小不董1 小时前
《Linux从小白到高手》理论篇:深入理解Linux的网络管理
linux·运维·服务器·数据库·php·dba
无敌少年小旋风2 小时前
MySQL 内部优化特性:索引下推
数据库·mysql