Redis--基础知识点--32--redis底层存储结构
Redis 数据库底层实现中,那个存储所有键值对的全局哈希表(dict),在运行过程中是会动态扩缩容的。
1. Redis 哈希表的结构特点
Redis 的数据库(如db->dict)底层使用的是dict 字典结构,它内部维护两个哈希表(ht[0] 和 ht[1]):
- 平时只用 ht[0]。
- 当需要扩容或缩容时,会分配一个 ht[1](大小是当前容量的 2 倍或 1/2 左右),然后渐进式地将 ht[0] 中的数据迁移到 ht[1],迁移完成后 ht[1] 成为新的 ht[0],旧的释放。
2. 触发扩容的条件
Redis 会检查负载因子:
负载因子 = 哈希表中已有节点数 / 哈希桶的数量(size)- 自动扩容:当负载因子 ≥ 1,且 Redis 没有在执行
bgsave/bgrewriteaof(即没有在后台持久化)时,就会触发扩容;如果正在持久化,负载因子需要达到5才扩容。 - 扩容规则:新的哈希表大小为当前键值对数量 × 2并取最近的 2 的幂。比如当前有 3 个键,容量为 4,扩容后容量为 8。
3. 触发缩容的条件
当键值对被删除,哈希表变得很空时,Redis 也会自动缩容,以节约内存。
- 自动缩容:当负载因子 < 0.1时,会触发缩容。
- 缩容规则:新的哈希表大小就是当前键值对的数量,然后按 2 的幂取整(但不会小于 4,除非空表)。例如当前 2 个键,容量原来是 16,缩容后容量为 4。
4. 渐进式 rehash(不阻塞服务)
无论是扩容还是缩容,都不是一次性把所有键重新哈希,因为这样会导致 Redis 阻塞几秒甚至更久。
Redis 采用了渐进式 rehash:
- 在 rehash 期间,每次对哈希表的增删改查操作,都会顺便把当前操作对应的桶从 ht[0] 迁移到 ht[1]。
- 此外,Redis 还会在空闲时间(serverCron 定时任务)主动迁移一批桶。
- 这样整个迁移过程被分摊到多次请求中,每个请求只增加微小开销,客户端无感知。
5. 手动控制(可选)
你也可以通过命令强制触发或调整 rehash 行为:
- 手动触发 rehash:
CONFIG SET activerehashing yes(默认开启) - 临时禁止 rehash:
CONFIG SET activerehashing no(不推荐) - 查看当前的 rehash 进度:
INFO stats中的total_active_defrag等字段,但 rehash 的具体状态需要看DEBUG OBJECT或MEMORY STATS。
⚠️ 一个容易混淆的点
不要把这个全局字典的动态扩缩容和Redis 集群(Cluster)的节点扩缩容搞混:
- 全局字典:单个 Redis 实例内部的哈希表自动 resize,默认就开启。
- Cluster 节点:是集群层面的节点增删,需要手动执行 resharding。
你问的是前者,Redis 内部确实是会动态扩缩容的,且这是其内存管理的重要特性之一。
如果你还想了解 rehash 期间如何同时访问两个哈希表、或者如何观测当前字典的扩容/缩容状态,我可以继续展开说明。
