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参数,优化内存使用和性能表现。

相关推荐
hoiii18713 分钟前
设置Redis在CentOS7上的自启动配置
数据库·redis·缓存
爬山算法18 分钟前
Redis(122)Redis的版本更新如何进行?
数据库·redis·bootstrap
thekenofdis7 小时前
Lua脚本执行多个redis命令提示“CROSSSLOT Keys in request don‘t hash to the same slot“问题
redis·lua·哈希算法
oneslide11 小时前
Kubernetes环境部署Redis集群
redis·容器·kubernetes
是垚不是土13 小时前
构建高可用Redis:哨兵模式深度解析与Nacos微服务适配实践
redis·微服务·bootstrap
小坏讲微服务17 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
hoiii18717 小时前
挂载配置文件以Docker启动Redis服务
redis·docker·eureka
C++chaofan18 小时前
基于session实现短信登录
java·spring boot·redis·mybatis·拦截器·session
q***333719 小时前
Redis简介、常用命令及优化
数据库·redis·缓存