656 字
3 分钟
Redis 的哈希表如何处理冲突和渐进式 rehash?
  1. 1Redis 系列导读:知识地图、必会主线与复习顺序
  2. 2Redis 中常见的数据类型有哪些?
  3. 3Redis 通常应用于哪些场景?
  4. 4Redis为什么这么快?
  5. 5Redis 常用的过期时间、删除 Key 命令有哪些?
  6. 6Redis 的过期 Key 是如何被删除的?
  7. 7Redis 内存满了怎么办?有哪些淘汰策略?
  8. 8缓存穿透、击穿、雪崩的区别与解决方案
  9. 9Redis 如何保证缓存与数据库的数据一致性?
  10. 10Redis 的持久化机制有哪些?
  11. 11Redis 主从复制的完整流程是什么?
  12. 12Redis 的哨兵机制是什么?
  13. 13Redis Cluster 模式与 Sentinel 模式的区别是什么?
  14. 14Redis 支持事务吗?如何实现?
  15. 15Redis 中如何实现分布式锁?
  16. 16Redis 的 Lua 脚本功能是什么?如何使用?
  17. 17如何解决 Redis 中的热点 Key 问题?
  18. 18Redis BigKey 有什么危害?如何发现和治理?
  19. 19为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
  20. 20Redis 的 LRU 和 LFU 有什么区别?
  21. 21Redis 数据类型和底层编码有什么区别?
  22. 22Redis 中跳表的实现原理是什么?
  23. 23Redis 的 ZSet 为什么使用跳表,而不是平衡树?
  24. 24Redis 的 RDB 快照如何生成?为什么会有写时复制?
  25. 25Redis 的 AOF 刷盘和重写有什么区别?
  26. 26Redis 断线后如何通过 PSYNC 部分重同步?
  27. 27Redis 主从切换为什么会丢数据?WAIT 能解决吗?
  28. 28Redis 集群会出现脑裂问题吗?
  29. 29Redisson 看门狗(watch dog)机制了解吗?
  30. 30Redis Cluster:哈希槽、Gossip 与故障转移
  31. 31Redis Pipeline 为什么能提高吞吐?能保证原子性吗?
  32. 32Redis 的 SCAN 和 KEYS 有什么区别?
  33. 33Redis 变慢时如何排查?SLOWLOG 能看到所有耗时吗?
  34. 34Redis 和 MySQL 有什么区别?
  35. 35Redis 为什么使用 SDS,而不是 C 字符串?
  36. 36Redis 的哈希表如何处理冲突和渐进式 rehash?本文
  37. 37Redis Cluster 的 MOVED 和 ASK 重定向有什么区别?
  38. 38Redis Cluster 为什么会报 CROSSSLOT?Hash Tag 怎么用?
  39. 39Redis 如何实现限流?固定窗口和滑动窗口怎么选?
  40. 40Redis Stream 如何保证消息消费?ACK 和 PEL 是什么?
  41. 41Redis 删除数据后为什么内存不下降?如何理解内存碎片?

Redis 广泛使用字典结构保存 Key 与其他索引。以 Redis 7.2 的经典实现为例,字典用哈希函数定位桶,冲突时通过链式结构组织条目;扩容或收缩时采用渐进式 rehash,分批迁移桶,减少一次迁移整个大表导致的长暂停。

为什么需要两个表?#

rehash 期间同时存在旧表和新表,并记录当前迁移位置。查找要考虑两张表,新的插入通常进入新表;每次推进迁移,就把旧表某些桶中的条目按新表大小重新计算位置。旧表迁移完毕后释放,新表成为当前表。

可以把它看成逐步搬仓库:旧仓和新仓都可能有货,收新货放进新仓,查货时同时考虑两个仓库。迁移不改变字典对外语义,但会增加暂时的内存与维护开销。

渐进式并不意味着每次操作严格只花固定时间。一个桶可能有多个冲突条目,分配新表本身也有成本。Redis 会在字典操作及后台工作中推进迁移,并在某些遍历或后台子进程情境下控制迁移,避免影响迭代或扩大 COW。具体策略属于版本实现细节。

为什么不能说查找永远 O(1)?#

哈希查找的常见平均成本接近 O(1),但取决于散列分布、负载和碰撞情况。极端冲突会增加遍历成本。Redis 采用合适的散列方式降低可预测碰撞风险,但平均复杂度不能被当成严格最坏情况保证。

常见追问#

rehash 和重新计算缓存 Key 是一回事吗?#

不是。rehash 调整内部哈希桶位置,业务 Key 的名字和 Value 不变;Cluster 扩缩容的哈希槽迁移是另一个层面的分片过程。

为什么不先迁移完再处理请求?#

大字典整体迁移会长期占用主线程,影响所有客户端。分批推进能把工作分摊到多次操作,但仍需监控尾延迟。

rehash 会不会暂时使用更多内存?#

会同时保留旧表和新表的桶数组,条目逐步移动。不能把两个表理解为完整复制两份所有 Value,但额外表空间不可忽略。

所有 Hash 类型都使用哈希表吗?#

不是。较小的 Hash 在相应版本中可以使用 listpack 等紧凑编码,只有符合条件转换后才使用字典存储。

Redis 的哈希表如何处理冲突和渐进式 rehash?
https://blog.xqcherry.top/posts/interview/redis/redis-hash-table-rehash/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0