面试题答案
一键面试渐进式rehash的具体过程
- 初始化阶段:
- 当Redis字典的负载因子达到阈值(例如负载因子大于1且字典正在扩展,或负载因子小于0.1且字典正在收缩)时,Redis会为字典分配一个新的哈希表。
- 此时,字典同时持有新旧两个哈希表,同时设置一个
rehashidx
属性为0,这个属性用于记录当前rehash的进度。
- 渐进式迁移阶段:
- 在进行字典的一些常规操作(如插入、查找、删除等)时,除了执行原本的操作外,还会顺带将旧哈希表中
rehashidx
索引位置上的所有键值对迁移到新哈希表中。 - 迁移完成后,
rehashidx
会自增1。 - 如此,随着字典操作的不断进行,旧哈希表中的键值对会逐步地被迁移到新哈希表中。
- 在进行字典的一些常规操作(如插入、查找、删除等)时,除了执行原本的操作外,还会顺带将旧哈希表中
- 完成阶段:
- 当
rehashidx
的值等于旧哈希表的大小,说明旧哈希表中的所有键值对都已迁移到新哈希表,此时释放旧哈希表,将新哈希表设置为当前字典的哈希表,并将rehashidx
设为-1,表示rehash操作完成。
- 当
如何在不影响Redis整体性能的前提下完成字典的扩展或收缩
- 分散负载:
- 渐进式rehash并非一次性将所有键值对从旧哈希表迁移到新哈希表,而是将迁移工作分散到字典的日常操作中。这样就避免了因一次性大量数据迁移而导致的长时间阻塞,保证了Redis对外服务的及时性和连续性。
- 不阻塞常规操作:
- 在进行rehash的过程中,Redis的常规操作(如读写数据)仍然可以正常进行。即使在迁移过程中,对于旧哈希表和新哈希表中的键值对,查找操作都能正确处理(先在新哈希表查找,若未找到再在旧哈希表查找),插入和删除操作也能保证数据一致性。
潜在的性能影响及Redis的应对方法
- 潜在性能影响:
- 额外内存消耗:在rehash过程中,由于同时存在新旧两个哈希表,会导致额外的内存消耗。
- 操作延迟增加:虽然每次操作只迁移少量键值对,但随着字典规模增大,每次操作额外的迁移时间可能会累积,导致部分操作延迟略有增加。
- Redis的应对方法:
- 内存管理:尽快完成rehash操作以减少额外内存占用时间。一旦负载因子达到阈值,就尽快开始rehash,并在日常操作中积极推进迁移工作。
- 控制操作延迟:通过合理设置负载因子阈值,避免在字典规模过大时才进行rehash,从而减少每次操作中迁移键值对的数量,控制操作延迟的增加。同时,Redis本身是单线程模型,在单线程环境下,减少了线程切换等开销,也有助于减少性能波动。