Redis 渐进式rehash怎么判定rehash完成了?

Redis 渐进式 Rehash 的完成判断机制

在 Redis 的字典(dict)结构扩容或缩容时,会使用 渐进式 Rehash 来避免一次性迁移所有键值对导致的阻塞。以下是判断旧哈希表(ht[0])是否全部迁移完毕的核心逻辑:


1. 渐进式 Rehash 的核心流程

Redis 的字典结构包含两个哈希表:

typedef struct dict {
    dictht ht[2];      // 两个哈希表(ht[0] 和 ht[1])
    int rehashidx;     // Rehash 进度标志(-1 表示未进行)
} dict;
  • ht[0]:当前使用的哈希表(旧表)。
  • ht[1]:扩容/缩容后的新哈希表。
  • rehashidx:记录当前迁移的桶索引(从 0 开始)。

2. 如何判断 Rehash 完成?

(1)迁移进度跟踪

  • rehashidx 表示旧表 ht[0]下一个待迁移的桶的索引
  • 每次触发 Rehash(如执行增删改查命令时),Redis 会迁移 ht[0]rehashidx 位置的桶到 ht[1],然后 rehashidx++

(2)完成条件

当满足以下条件时,认为 Rehash 完成:

if (rehashidx == ht[0].size) {
    // 1. 释放 ht[0] 的内存
    free(ht[0].table);
    // 2. 将 ht[1] 设置为 ht[0]
    ht[0] = ht[1];
    // 3. 重置 ht[1] 为空表
    _dictReset(&ht[1]);
    // 4. 关闭 Rehash 标志
    rehashidx = -1;
}
  • rehashidx == ht[0].size:表示所有桶(从 0 到 size-1)均已迁移。
  • 此时旧表 ht[0] 被释放,新表 ht[1] 替换为 ht[0]rehashidx 重置为 -1

3. 触发迁移的时机

Redis 在以下操作中 逐步迁移一个或多个桶

  1. 增删改查命令(如 GETSETDEL):
    • 每次命令执行时,迁移 ht[0]rehashidx 位置的桶。
  2. 定时任务(serverCron
    • 在事件循环中,Redis 会主动迁移一定数量的桶(默认每次 1 个桶)。

4. 为什么需要渐进式 Rehash?

  • 避免阻塞:如果一次性迁移所有键值对,在大字典时会导致 Redis 短暂无响应。
  • 分摊开销:将迁移成本分散到每次操作中,保证高性能。

5. 访问数据时的逻辑

在 Rehash 过程中,数据访问需检查两个表:

value = dictFind(key):
    if dict->rehashidx != -1:
        // 1. 先在 ht[0] 查找
        if (entry = ht[0][hash(key) % ht[0].size]) != NULL:
            return entry.value
        // 2. 如果 ht[0] 未找到,继续查 ht[1]
        return ht[1][hash(key) % ht[1].size]
    else:
        // 未在 Rehash,直接查 ht[0]
        return ht[0][hash(key) % ht[0].size]

总结

  • 完成标志:当 rehashidx 等于旧表 ht[0] 的大小时,表示所有桶已迁移。
  • 渐进式迁移:通过分散到每次操作和定时任务,避免集中式阻塞。
  • 数据访问:Rehash 期间需同时查询 ht[0]ht[1]

参考源码:Redis dict.c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java干货仓库

觉得写的不错,就给博主投币吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值