在 Redis 中,渐进式 rehash 是一种策略,用于在后台逐步完成哈希表的扩容或缩容,确保在进行 rehash 时不会阻塞主线程太长时间,影响 Redis 服务器的响应能力。以下是渐进式 rehash 的实战详解:
渐进式 rehash 过程
-
触发 rehash:
当 Redis 字典(dictionary)中的键值对数量增长到一定程度,负载因子(已存储键值对数量 / 哈希表大小)超过了预设阈值时,Redis 会启动 rehash 过程,目的是创建一个新的更大或更小的哈希表。 -
分配新哈希表:
Redis 会为字典分配一个新的哈希表(通常容量翻倍),将其命名为ht[1]
,而原有的哈希表成为ht[0]
。 -
渐进式迁移:
- 开始 rehash 过程时,Redis 不会立即一次性迁移所有键值对,而是设置一个全局变量
rehashidx
,初始值为 0。 - 在后续的读写操作(包括增删查改)过程中,每次操作前都会检查
rehashidx
是否小于ht[0]
的大小。 - 若
rehashidx
小于ht[0]
大小,Redis 就会从ht[0]
的rehashidx
索引位置开始,将该索引所对应的链表中的所有键值对迁移到ht[1]
相应的哈希桶中,并将rehashidx
加一。 - 这样,每次操作都会迁移一部分键值对,直到整个
ht[0]
中的所有键值对都被迁移到了ht[1]
。
- 开始 rehash 过程时,Redis 不会立即一次性迁移所有键值对,而是设置一个全局变量
-
临时双表查询:
在 rehash 进行期间,字典会同时使用ht[0]
和ht[1]
进行查找操作。如果在ht[0]
中未找到目标键,Redis 会接着在ht[1]
中查找,确保在此期间所有的键都能被正确访问。 -
完成 rehash:
当rehashidx
达到ht[0]
的大小时,说明 rehash 过程已完成。此时,Redis 会将ht[1]
替代ht[0]
成为新的主哈希表,并释放掉旧的ht[0]
,同时重置rehashidx
为-1
,等待下次需要 rehash 时再次启用。
通过这种方式,Redis 能够在不影响主线程服务请求的情况下逐渐完成哈希表的扩容或缩容,极大地降低了对系统性能的影响。