Redis的底层数据结构

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-sizelist-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-entrieshash-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-entrieszset-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 会根据配置参数自动在这些底层实现之间转换:

  1. 当元素数量或大小超过阈值时,从小内存结构转为大内存结构
  2. 转换是单向的,不会自动转回去
  3. 可以通过修改配置参数调整转换阈值

为什么采用多种底层实现?

  1. 内存效率:对小数据使用紧凑存储(如ziplist)
  2. 性能优化:对不同操作提供最优时间复杂度
  3. 灵活性:根据数据特征自动选择最佳结构
  4. 平衡性:在内存使用和CPU效率之间取得平衡

理解这些底层实现有助于合理配置Redis参数,优化内存使用和性能表现。

相关推荐
爬山算法1 小时前
Redis(169)如何使用Redis实现数据同步?
前端·redis·bootstrap
武帝为此2 小时前
【Redis 数据库介绍】
数据库·redis·缓存
铁锚2 小时前
Redis中KEYS命令的潜在风险与遍历建议
数据库·redis·缓存
爬山算法3 小时前
Redis(168) 如何使用Redis实现会话管理?
java·数据库·redis
可爱の小公举4 小时前
Redis技术体系全面解析
数据库·redis·缓存
Geoking.7 小时前
Redis 中 ziplist 与 quicklist 解析与对比
数据库·redis·缓存
Eren7Y琳7 小时前
开箱即用构建应用环境:openEuler易获得性深度验证
redis·设计模式·架构
萝卜青今天也要开心8 小时前
2025年下半年系统架构设计师考后分享
java·数据库·redis·笔记·学习·系统架构
阿伟*rui8 小时前
互联网大厂Java面试:音视频场景技术攻防与系统设计深度解析
java·redis·websocket·面试·音视频·高并发·后端架构
DemonAvenger8 小时前
Redis集群架构详解:从单机到分布式的扩展之路
数据库·redis·性能优化