redis字典通过ht[0]和ht[1]双表及rehashidx实现渐进式rehash:ht[0]为主用表,ht[1]为迁移目标表,rehashidx≥0时标识当前待迁移桶索引,每次命令顺带迁移一桶并自增,确保不阻塞服务且数据一致。

Redis 字典通过 ht[0] 和 ht[1] 两张哈希表配合 rehashidx 索引,实现边服务边迁移的渐进式 rehash,不阻塞读写请求。
ht[0] 和 ht[1] 各自的作用
字典结构中始终维护两个哈希表:
- ht[0] 是当前正在使用的主表,所有常规增删改查都优先操作它
- ht[1] 是空闲表,仅在 rehash 触发时被分配新空间(如扩容为原 size 的 2 倍,或缩容为 used/2 的最近 2n)
- rehash 开始后,ht[1] 逐步接收从 ht[0] 迁移来的数据;迁移完成前,两表并存
rehashidx 控制迁移进度
rehashidx 是一个有符号整数,标记当前迁移位置:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 值为 -1:表示未进行 rehash,所有操作只访问 ht[0]
- 值 ≥ 0:表示正在 rehash,该数值即为 ht[0] 中下一个待迁移的桶索引(如 rehashidx == 5,说明索引 0~4 已迁完,正准备处理第 5 个桶)
- 迁移时,把 ht[0] 中该索引位置上的整条链表(可能含多个 dictEntry)一次性搬入 ht[1] 对应的新位置
每次请求如何参与迁移
Redis 不开单独线程,而是在每次处理客户端命令时“顺手”推进一小步:
- 收到任意命令(GET、SET、HGET 等)时,先检查 rehashidx ≥ 0,若正在 rehash,则执行一次桶迁移
- 迁移完成后,rehashidx 自增 1;若已迁完所有桶(即 rehashidx == ht[0].size),则释放 ht[0],将 ht[1] 赋给 ht[0],rehashidx 重置为 -1
- 查找操作会同时检查 ht[0] 和 ht[1]:先查 ht[0],未命中再查 ht[1];写操作只写 ht[0],但新增 key 若落在已迁移的桶范围,实际会直接写入 ht[1]
为什么能保证数据不丢、不乱
关键在于迁移逻辑与操作语义严格对齐:
- 迁移过程是原子的——每次只搬一整条链表,不会出现“半条链表在旧表、半条在新表”
- 所有写操作都会触发 rehash step,确保迁移持续向前;即使无请求,定时任务也会每 100ms 主动推进至少 1 步
- 删除操作会同时清理 ht[0] 和 ht[1] 中匹配的节点;过期判断也覆盖两张表
- 新插入的 key 总是根据当前状态决定写入哪张表:若 rehash 进行中,新 key 按其 hash 值计算在 ht[1] 中的位置直接写入










