it编程 > 数据库 > Redis

Redis中dictht和dict的实现

51人参与 2026-08-31 Redis

dictht (字典哈希表)

dictht 是 “dictionary hash table” 的缩写,它代表一个最基础的哈希表结构。

它的定义如下(源码在 src/dict.h):

typedef struct dictht {
    dictentry **table;      // 指向一个 bucket 数组(指针的指针)
    unsigned long size;     // 哈希表的大小(bucket 数组的长度)
    unsigned long sizemask; // 用于计算索引值的掩码,总是等于 size-1
    unsigned long used;     // 哈希表中已有节点的数量
} dictht;

对每个字段的解释:

一个 dictht 的结构示意图:

        dictht
+------------------+
|      table       |----->  [dictentry*] -> [dictentry] -> [dictentry] -> null   (index 0)
|                  |        [dictentry*] -> null                                 (index 1)
|     size: 4      |        [dictentry*] -> [dictentry] -> null                  (index 2)
|  sizemask: 3     |        [dictentry*] -> [dictentry] -> [dictentry] -> null   (index 3)
|     used: 8      |
+------------------+

(上图展示了一个大小为 4 的哈希表,存储了 8 个元素,说明发生了哈希冲突,并用链表法解决)

2. 核心概念:dict (字典)

dict 是 redis 字典的主结构体,它封装了两个 dictht 和一些管理功能,使得哈希表能够平滑地扩容和缩容(rehashing)。

它的定义如下:

typedef struct dict {
    dicttype *type; // 类型特定函数,为实现多态而存在
    void *privdata; // 私有数据,传递给类型特定函数的可选参数
    dictht ht[2];   // 两个哈希表,为什么是两个?请看下面的解释
    long rehashidx; // rehashing 的进度,如果不是 -1 则表示正在进行 rehash
    int16_t pauserehash; // rehashing 暂停标志,>0 时表示 rehash 被暂停
} dict;

对每个字段的详细解释:

3. dictht 和 dict 的关系与协作:rehashing

dictht 是静态的存储单元,而 dict 是动态的管理器。它们最精妙的协作体现在 rehashing(重新散列) 过程中。

为什么需要 rehashing?

随着操作不断执行,哈希表的负载因子 used/size 会变得过大(冲突增多,效率下降)或过小(浪费内存)。为了维持高效性能,需要在适当的时候对哈希表进行扩容或缩容。

rehashing 的过程(渐进式重新散列)

  1. 触发:当满足一定条件时(如负载因子 > 1 且没有在进行 bgsave,或 > 5 等),触发扩容。为 ht[1] 分配空间,大小为第一个大于等于 ht[0].used * 2 的 2 的幂(例如 used=5,则新 size 为 16)。如果是缩容,则大小为第一个大于等于 ht[0].used 的 2 的幂(2的幂取模的时候直接与很方便)。
  2. 将 dict 的 rehashidx 从 -1 设置为 0,表示 rehashing 正式开始。
  3. 渐进式迁移:redis 不会一次性将 ht[0] 的所有键值对都迁移到 ht[1](如果表很大,这会阻塞服务器很长时间)。而是采用分而治之的策略,将迁移工作分散到后续的每次增、删、改、查命令中。
    • 每当对字典进行任何操作时,除了执行指定的操作,还会顺带将 ht[0] 在 rehashidx 索引上的整个 bucket 链表迁移到 ht[1] 中。
    • 迁移完成后,将 rehashidx 的值加 1。
  4. 完成:当 rehashidx 递增到 ht[0].size 的值时,意味着 ht[0] 的所有数据都已迁移完毕。此时,释放 ht[0] 的空间,将 ht[1] 设置为新的 ht[0],并为 ht[1] 创建一个新的空白哈希表以备下次使用。最后,将 rehashidx 重置为 -1。

在 rehashing 期间如何查找?
查找一个键时,会同时查找 ht[0] 和 ht[1] 两个表,先查 ht[0],如果没找到再查 ht[1]。

总结与对比

特性dictht (字典哈希表)dict (字典)
角色数据存储单元,一个静态的哈希表数组字典管理器,一个动态的、封装好的字典对象
核心功能存储键值对数据,处理哈希冲突(链表法)管理两个 dictht,实现类型多态,控制 rehashing 流程
包含关系被 dict 所包含包含两个 dictht (ht[0] 和 ht[1])
rehashing是 rehashing 操作的对象是 rehashing 过程的控制器(通过 rehashidx)
类比像是房子的毛坯房(只有房间结构)像是房子的业主+装修队(负责管理、维护、扩建房子)

简单来说:

这种“一个管理器 + 两个存储单元”的设计是 redis 字典实现高效、稳定且能够渐进式扩容的关键。

dict的rehash

渐进式rehash(防止主进程被长时间阻塞)

到此这篇关于redis中dictht和dict的实现的文章就介绍到这了,更多相关redis dictht和dict内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

Redis键值存储的实现示例

08-31

NGINX白名单的几种方法实现

08-29

Redis Zset的实现原理详解

08-28

Redis Ziplist压缩列表的实现

08-28

Redis中EXPIREAT命令实现

08-28

Redis 中实现分布式锁

09-02

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论