Redis扩容不阻塞服务靠渐进式rehash:维护ht[0]和ht[1]双表,命令执行后迁移一个桶,读查ht[1]再ht[0],写新key入ht[1]、旧key更新在ht[0],空闲时也推进迁移。

Redis 哈希表扩容不阻塞服务,核心靠的是“边服务、边迁移”的渐进式 rehash 机制,而不是一次性搬完所有数据。
双哈希表结构是基础
Redis 的字典(dict)内部始终维护两个哈希表:ht[0](当前主表)和 ht[1](迁移目标表)。正常情况下只用 ht[0];触发扩容时,Redis 会为 ht[1] 分配新空间(通常是 ht[0].used × 2 的最近 2 的幂),但不会立刻把所有数据搬过去。
- ht[0] 继续响应所有读写请求
- ht[1] 初始为空,仅作为迁移目的地
- rehashidx 字段标记迁移进度(-1 表示未开始,≥0 表示正从该索引位置开始迁移)
迁移任务被拆解到日常操作中
每次执行增、删、改、查命令(如 GET、SET、HGET、DEL 等),Redis 都会在处理完业务逻辑后,顺带迁移 一个桶(bucket) 的全部数据——即 ht[0] 中 rehashidx 指向的那个数组槽位及其链表上的所有键值对。
- 迁移完成后,rehashidx 加 1,指向下一个待迁桶
- 若当前桶为空,rehashidx 直接跳到下一个非空桶
- 整个过程对客户端完全透明,单次操作延迟几乎无感知
查询与写入自动兼容新旧两张表
在 rehash 进行中,Redis 对数据访问做了特殊处理:
- 读操作:先查 ht[1],没找到再查 ht[0];确保新旧表的数据都能命中
- 写操作:新 key 总是插入到 ht[1];已存在的 key 更新仍在 ht[0] 上进行(避免重复或丢失),同时该 key 所在桶会被立即迁移
- 删除操作:在两张表中都尝试删除,保证清理彻底
空闲时间也会推进迁移
除了命令驱动,Redis 还利用服务器的空闲周期(比如每次事件循环间隙)主动执行若干步迁移,加快收尾速度。当 rehashidx 最终变为 -1,表示 ht[0] 全部清空,此时释放 ht[0] 内存,ht[1] 升级为新的 ht[0],整个扩容完成。











