资讯动态

《系统架构师成长之路》第 5 期|数据结构与算法:哈希表与一致性哈希——从 O(1) 查找到分布式分片

发布时间:2026/10/24 4:11:48 来源:尧图企业网站定制
《系统架构师成长之路》第 5 期数据结构与算法哈希表与一致性哈希——从 O(1) 查找到分布式分片导读前 4 期我们走完了内存 → 传输 → 协议本期回到架构师最常挂在嘴边、却也最容易被低估的数据结构——哈希表。单机里它给你 O(1) 查找到了分布式key % N的取模分片会在扩容瞬间引发缓存雪崩。本期先把 O(1) 的数学基础推一遍再推导一致性哈希如何把扩容影响从 90% 压到 1/N。一、哈希表O(1) 从哪来哈希表 哈希函数 一段连续数组槽位。插入/查找时插入 key槽位 hash(key) mod m放入该槽冲突则处理 查找 key槽位 hash(key) mod m到该槽找为什么平均 O(1)关键在于槽位数 m 与元素数 n 的比例——定义装载因子α n / m 元素数 / 槽位数推导链表法平均查找长度逐步若哈希均匀每个槽平均挂 α 个元素n 个元素均匀撒到 m 个槽n/m α查找成功目标元素所在链表它排在链表中的平均位置 该链表长度的 1/2对目标元素所在链表期望长度 1 该链表其他元素的期望数。其他 n−1 个元素落入这一特定槽的概率各为 1/m故期望长度为1 (n−1)/m ≈ 1 α/2 成功查找的平均比较次数查找失败需遍历完整个链表平均比较次数 链表的期望长度 1 α只要 α 被控制在常数如 0.75Java HashMap 的扩容阈值平均比较次数就是常数 →O(1)。技巧这里用的是期望/平均分析——哈希函数是否均匀决定了这个结论是否成立所以哈希函数质量是哈希表性能的第一前提。图5-3哈希表主体hash(key) % m决定槽位多个 key 落入同一槽时以链表串接装载因子 αn/m 控制链表平均长度。冲突处理两大流派方案思路代价链表法chaining冲突元素挂链表指针开销缓存不友好开放寻址open addressing冲突后找下一个空槽线性探测/二次探测装载因子必须 1删除需打标工程实例JavaHashMap用链表法链表长度 ≥8 转红黑树退化保护Redis 字典用链表法 渐进式 rehash扩容不阻塞服务。二、分布式分片key % N的致命伤单机哈希要扩容怎么办——取模分片N 台节点key放到hash(key) % N号节点。推导扩容为何雪崩逐步原 N3key的归属 hash(key) % 3扩容到 N4归属变成hash(key) % 4一个 key 能留在原节点必须同时满足hash(key) % 3 原节点且 hash(key) % 4 原节点对均匀哈希hash(key) % 4 hash(key) % 3只对约 1/4 的 key 成立同余条件概率 ≈ 1/N结论扩容 3→4 时约 3/4 的 key 换了节点。若这些 key 是缓存键扩容瞬间 3/4 的缓存失效全部打回数据库 →缓存雪崩。失效比例 ≈ 1 − 1/(N1) N/(N1) 从 N 扩到 N1工程代价取模分片扩容 全量重哈希 缓存穿透 数据库打爆。这也是为什么不用取模的经典答案。三、一致性哈希让扩容只影响 1/N思路把哈希空间组织成环0 ~ 2³²−1 首尾相接节点与 key 都哈希到环上key 归属 从 key 的位置出发顺时针遇到的第一个节点图5-1一致性哈希环节点 A/B/C/D 分布在环上key 沿顺时针找归属新增节点 X 只接管环上 X→D 之间的一小段。推导加节点影响比例逐步环总长 2³²N 个节点均匀分布时相邻节点间的平均弧长 2³²/N新增节点 X 落在环的随机位置它只会接管从 X 逆时针到前一个节点这段弧上的 key这段弧的期望长度 相邻节点平均间距 2³²/N均匀分布下任意落点与前驱间距期望 1/(N1)·环长 ≈ 2³²/N结论加一个节点只有约 1/(N1) 的 key 迁移——相比取模的 N/(N1)影响比例反过来了。取模分片扩容影响N/(N1) ≈ 全部失效 一致性哈希加节点影响1/(N1) ≈ 只有一小段迁移数据倾斜与虚拟节点真实节点只有 N 个环上位置随机可能扎堆 → 负载不均。解法每个物理节点在环上放k 个虚拟节点如 k160把一个节点变成160 个均匀撒点统计上负载更均衡推导直觉独立同分布样本越多方差越小。Redis Cluster、Cassandra、Memcached 客户端均采用该思想。图5-2虚拟节点物理节点 A/B 各映射到多个环上位置A₁、A₂…B₁、B₂…减少扎堆导致的负载不均。四、架构视角哈希在系统设计中的位置场景用到的哈希思想缓存分片Redis Cluster一致性哈希 虚拟节点16384 个 slot 的槽位设计数据库分库分表一致性哈希环或范围分片扩容平滑负载均衡一致性哈希 LB同一 client key 固定到同一后端会话保持去重/计数Bloom Filter多个哈希函数映射位数组常见坑① 哈希函数选得差如直接取模字符串 hash 的偶分布导致倾斜② 虚拟节点 k 太小热点 key 仍扎堆③ 删除节点后没有数据迁移策略如 rehash 窗口会造成短暂 miss④ 一致性哈希不解决热点 key个别 key 访问量爆炸需额外做热点检测与本地缓存。小结哈希表 O(1) 的前提是装载因子可控 哈希均匀链表法成功查找期望 1α/2 次比较取模分片扩容失效比例 N/(N1)几乎全量重映射是缓存雪崩的元凶一致性哈希把扩容影响压到 1/(N1)只有新节点与前驱之间的环段迁移虚拟节点k≈160把物理节点打散成均匀撒点解决数据倾斜。思考题Java HashMap 为什么在链表长度 ≥8 时转红黑树用最坏 O(n) vs 退化概率推一下。Redis Cluster 用 16384 个固定 slot 而不是一致性哈希环为什么对比两者的扩容代价。一致性哈希环上如果删掉一个节点它的 key 全部迁移给下一个节点——如何避免下一个节点瞬间过载下期预告第 6 期「设计原则与设计模式SOLID——从面条代码到可维护架构」——用一次订单系统重构串起五个原则推导依赖倒置如何让高层不依赖低层细节。参考资料CLRS《算法导论》第 11 章哈希表链表法与开放寻址装载因子分析一致性哈希论文Karger et al., “Consistent Hashing and Random Trees”1997Redis Cluster 官方文档slot 与哈希槽设计《Redis 设计与实现》黄健宏渐进式 rehash、字典实现美团技术博客《Java HashMap 详解》红黑树化阈值分析Martin Kleppmann, “Designing Data-Intensive Applications” 第 6 章分区一致性哈希与倾斜

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑