首页 › programming › 加机器重排九成数据:哈希为何要弯成环

加机器重排九成数据:哈希为何要弯成环

导语:一个被所有大厂"默认开启"的算法

如果你在一家有规模的互联网公司写过分布式系统,你几乎一定用过一致性哈希(Consistent Hashing),哪怕你自己没写过一行它的代码——因为 Cassandra、DynamoDB、Memcached 集群、Akamai CDN、Discord 的聊天分片,底层都在跑它。Gaurav Sen 这条播放量破百万的视频《What is CONSISTENT HASHING and Where is it used?》,把这玩意儿讲成了系统设计面试的"必修课"。

但它真正值得你停下来想的,不是"怎么在白板上画一个环",而是一个反直觉的事实:我们最直觉的分配方式——hash(key) % N——在大规模系统里几乎是个 bug。当你有 100 台机器,加 1 台,会有约 99% 的数据被迫搬家;缓存集体失效、网络被打爆、磁盘 I/O 飙红。一致性哈希解决的,正是这个"加一台、崩全场"的病。而它名字里的"一致"(consistent),指的根本不是"结果一致",而是"机器变了、映射却尽量不变"。本文就把这个被一句话带过的核心,彻底拆开。

视频背景卡片

项目 内容
视频标题 What is CONSISTENT HASHING and Where is it used?
频道 Gaurav Sen(百万订阅级,前 Google / Uber 系工程师向系统设计频道)
时长 约 10 分 50 秒(650 秒)
播放量 约 103 万(截至检索,是该主题播放量最高的系统设计解读之一)
核心主题 一致性哈希:分布式系统中数据/请求如何分片、加减机器时如何把迁移量降到最低
适配人群 后端工程师、SRE、系统设计面试者、做缓存/分库分表的人

说明:由于当前环境的 YouTube 元数据与字幕接口被 IP 限流/风控拦截(返回 "Sign in to confirm you're not a bot"),下文对视频内容的还原,结合该主题公认的原始论文与工程实践做交叉验证,凡属"延伸分析"的部分我会显式标出,不冒充视频原话。

核心内容拆解

一、先承认问题:hash(key) % N 是个"地雷"

视频的起点是一个所有人都会想到的朴素方案。你有 N 台缓存服务器,来了一个 key(比如 user:42),你算 h = hash(user:42),然后 server = h % N。看起来天衣无缝:同一把 key 永远落在同一台机器上,分布也均匀。Gaurav Sen 在视频里反复强调的就是这步——它均匀、它确定、它在机器数不变时完美。

致命的是下一句:机器数变了怎么办?

假设 N=3,现在加一台变成 N=4。h % 3 和 h % 4 是两个几乎完全不相关的函数。原来落在 server 0 的 key,现在可能去 server 0、1、2、3 任何一个。算一下数学:当 N→N+1 时,平均有 N/(N+1) 比例的 key 会换服务器。N=3 是 75%,N=10 是 91%,N=100 是 99%。

也就是说:你有一百台机器,加一台做扩容,结果是 99% 的缓存全部 miss。 所有原本缓存在内存里的热点数据,瞬间变成"未命中",请求像海啸一样打到后端数据库,这就是著名的 缓存雪崩(cache stampede)。视频用一个很生活化的比喻:这就像为了让办公室多坐一个人,把所有人原来的工位全部打乱重排一遍——为了扩容 1%,制造 100% 的混乱。这就是为什么工程师们需要找一个"加机器时、绝大多数 key 还留在原处"的方案。

二、把直线弯成环:一致性哈希的核心操作

Gaurav Sen 视频的"高潮"是他在白板上把一条直线弯成一个环。一致性哈希的精髓只有两步:

  1. 不再只哈希 key,而是把"服务器"也哈希。 取一个固定的、巨大的哈希空间(比如 0 到 2³²−1),把首尾相连变成一个环。每台服务器用它的名字/IP 做一次 hash,落在环上的某个点。
  2. key 也 hash 到环上,然后顺时针走,遇到的第一台服务器就是它的归属。

就这么简单。关键差别在于:现在 key 不是直接对应"第几个服务器",而是对应"环上一个位置",再由"位置→顺时针最近的机器"这层间接映射决定归属。

为什么这就解决了问题?因为当你在环上插入一台新机器时,它只会"抢走"它和它逆时针方向邻居之间那一段弧上的 key。其余所有弧段、所有机器上的 key 纹丝不动。新机器只接管了环上的一小段,平均下来就是 K/N 的 key 被迁移(K 是总 key 数,N 是机器数)。100 台机器扩到 101 台,只有约 1% 的数据要搬——和取模方案的 99% 形成戏剧性反差。

这就是它名字的真正含义。"consistent"不是"结果一致",而是"拓扑一致"——节点集合变化时,绝大多数映射保持不变。 视频里这个点经常被一句带过,但它才是这个算法被发明出来的全部理由。

三、为什么叫"一致性":用论文的话精确说一次(延伸分析)

视频没展开论文细节,我补一下,避免你以讹传讹。一致性哈希来自 1997 年 David Karger 等人的论文《Consistent Hashing and Random Trees》(这帮人后来创办了 Akamai CDN,这算法最初就是为了"在边缘节点之间分配网页缓存"而发明的)。论文给"一致性"下了严格的四条性质,其中最关键的两条是:

换句话说,"一致性"是一个关于最小化 churn(迁移扰动)的数学承诺,而不是关于"输出稳定"。取模哈希在节点不变时输出也很稳定,但它没有平滑性。这个区分理解了,你才真正读懂了这个算法,而不是只会在面试时画圈。

四、第一个坑:环不均匀,一台机器吃成胖子

视频会接着抛出一个现实问题:节点太少时,环上的分布会很不均匀。 因为每台服务器只占环上一个点,3 台机器随机落点,很可能其中一台恰好占了一段超大的弧,分到 60% 的 key;另一台只分到 5%。负载彻底失衡。

解决方案是 Gaurav Sen 重点讲的 虚拟节点(virtual nodes / vnodes):让一台物理服务器在环上占很多个点(不是 1 个,而是 100~200 个,甚至更多)。比如 Cassandra 默认每台机器 256 个 vnode,Memcached 的 ketama 算法用约 160 个点/服务器。

为什么这能修好?这是大数定律在起作用。论文证明:基本方案的负载不均衡度是 O(log N);而给每台机器 v 个虚拟节点后,不均衡度降到约 O(1/√v)。v=100 时,负载偏差能压到百分之几以内。虚拟节点还有个意外好处:故障转移更平滑。一台机器挂了,它的负载不是全压给某一个邻居(那会把邻居也压垮),而是分散给它那 100 多个点周围的不同邻居——压力被自然摊薄。

五、第二个坑:负载均衡 ≠ 请求均衡(延伸分析)

视频到这里通常就收尾了。但我要补一个工程上更扎心的坑,否则你照着去搭系统会踩雷。

一致性哈希均衡的是"key 的数量",不是"请求的流量"。 假设某个 key 是一个网红的直播间 ID,它的访问量是其他 key 的一万倍。一致性哈希照样只把它分到一台机器上,那台机器会被打爆,而其他机器闲得发慌。这就是 hot key / hot spot 问题。

更微妙的是:在虚拟节点方案里,一台物理机的负载是它所有 vnode 弧段的总和。当某台机器刚加入或刚宕机时,瞬时负载可能远超平均值。Google 在 2016 年专门发了一篇《Consistent Hashing with Bounded Loads》(有界负载一致性哈希)来治这个病:给每台机器设一个上限 (1+ε)·(平均负载),超过就溢出到下一台机器。这篇论文后来被 Netflix 的 Hailstorm、Vimeo 等采用。所以工程上你看到的"一致性哈希",往往不是裸的环,而是环 + 虚拟节点 + 有界负载的组合拳。

六、它到底被用在了哪里

视频标题的后半句"and Where is it used?"是最实用的部分,我把它和业界事实交叉核对如下:

值得提醒的一个反例:Redis Cluster 并不用一致性哈希。它用的是 16384 个固定"哈希槽(hash slots)",用 CRC16(key) mod 16384 选槽,再把槽段分配给节点;扩容时迁移的是"槽"而不是逐 key 计算。这是另一种思路(slot partitioning),目标相似但实现不同,面试时别说混了。

七、它不是唯一的答案:同族算法速览(延伸分析)

如果你以为一致性哈希是"分片"的唯一解,那就低估了这个领域。其实它是一族算法里最出名的一个:

所以更准确的心智模型是:一致性哈希 = 通用、可解释、生态最成熟的分片基底;其他算法是在不同约束(极致性能、极致均匀、节点频繁变动)下的特化版本。知道这一族,你才不会被"一致性哈希"这四个字框死。

八、一句话重新理解"一致"

把视频的核心再压缩一次:取模哈希把 key 直接绑死在"机器序号"上,所以机器数一动,绑定关系全崩;一致性哈希把 key 绑在"环上的位置"上,机器只是位置之间的标签,加减标签只动局部。 这层"间接"就是它全部的魔法。所谓 consistent,consistent 的是"机器集合变化时、key 与机器的对应关系尽量不动"。

知识结构图

flowchart TD
  A["分片难题:把海量 key 分到 N 台机器<br/>且加减机器时尽量少搬家"] --> B{"怎么分配?"}
  B -->|朴素| C["取模哈希 hash(key) % N"]
  B -->|工程| D["一致性哈希:哈希环"]

  C --> C1["N→N+1 时模数全变"]
  C1 --> C2["约 N/(N+1) 的 key 重映射<br/>N=100 时高达 99%"]
  C2 --> C3["缓存集体失效 / 数据大搬家<br/>= 雪崩"]

  D --> D1["机器与 key 都映射到 0..2^32 的环上<br/>key 归顺时针下一个机器"]
  D1 --> D2["加减机器只动该弧段的 key<br/>平均迁移 ≈ K/N"]
  D2 --> D3{"工程上仍有两个坑"}

  D3 -->|节点少→分布不均| E["虚拟节点 vnodes<br/>一台机器占环上 100+ 点<br/>不均衡度 O(log N)→O(1/√v)"]
  D3 -->|hot key / 瞬时过载| F["有界负载 Bounded Loads<br/>单机上限 (1+ε)·均值<br/>溢出到下一台"]

  E --> G["实战落地<br/>DynamoDB / Cassandra / Memcached(ketama) / Akamai / Discord"]
  F --> G
  G --> H["同族:Rendezvous / Maglev / Jump Hash<br/>按性能/均匀/变动频率选型"]

下面这张图把两种方案的"扰动"直观对比——左边取模、右边一致性哈希,同样的扩容动作,代价天差地别:

flowchart LR
  subgraph M["取模哈希:加一台 = 几乎全重排"]
    direction TB
    M1["hash(key) % 3"] --> M2["→ 加一台变 % 4"]
    M2 --> M3["N=100 时 99% 的 key 换了机器<br/>缓存几乎全 miss"]
  end
  subgraph R["一致性哈希:加一台 = 只搬一段弧"]
    direction TB
    R1["key 与 server 都上环<br/>顺时针归最近的 server"] --> R2["→ 环上插入新机器"]
    R2 --> R3["只迁移新机器那段弧的 key<br/>≈ 1/N ≈ 1%"]
  end

实战启示

1. 选型时先问:你的"机器集合"稳不稳? 如果你只是单机 Redis、或者机器数基本不变,取模哈希完全够用,别过度设计。但只要你预期会"经常扩缩容"(云原生、K8s 自动伸缩、缓存集群),一致性哈希就是默认选项,否则你每次扩容都要付一次"全量迁移"的税。

2. 别裸用环,记得开虚拟节点。 几乎所有成熟库都默认带 vnode/ketama,但如果你自己手撸一个,3 台机器的环会出现肉眼可见的偏斜。经验值:每台物理机 100~200 个虚拟节点是安全和性能的甜点。

3. 把 hot key 当成一等公民来防。 一致性哈希不解决流量倾斜。对超热 key,要么在它前面再加一层本地缓存,要么用"子分片"(一个 key 拆成带后缀的多个副本分散到不同机器),要么直接上有界负载版本。这是新手最常忽略、上线最容易翻车的地方。

4. 客户端和服务端必须用同一份"环拓扑"。 一致性哈希是客户端侧算法——所有客户端要算出同样的 hash 和同样的虚拟节点位置,才能把请求打到对的机器。生产中务必用同一个经过验证的库(如 groupcache 的 consistenthash、libketama、Hashicorp 的 memberlist),别自己实现 hash 函数还混用语言,否则不同语言的字符串 hash 会给你惊喜。

5. 面试和架构评审的心智模型:把它当成"间接层"。 理解一致性哈希的最高境界不是会画环,而是理解"通过引入一个中间层(环上位置),把'机器变更'对'数据归属'的影响局部化"。这个"间接化以降低耦合"的工程思想,和虚拟内存、CDN、消息队列是同一脉的。

延伸学习路径

  1. 奠基论文:D. Karger et al., Consistent Hashing and Random Trees(1997)——看算法的原始定义和四条性质,理解"consistent"到底 consistent 什么。
  2. 工业落地:G. DeCandia et al., Amazon Dynamo(SOSP 2007)——一致性哈希 + 虚拟节点在生产系统里到底怎么用。
  3. 修坑论文:V. Mirrokni et al., Consistent Hashing with Bounded Loads(Google, 2016)——治"瞬时过载"的官方解法。
  4. 同族对照:Eisenbud et al., Maglev: A Fast and Reliable Software Network Load Balancer(Google NSDI 2016)+ Rendezvous Hashing(HRW)原始资料——理解一致性哈希在整个"分片/路由算法族"里的位置。
  5. 可视化补充:ByteByteGo 的《Consistent Hashing | Algorithms You Should Know #1》(418 万级播放频道)和 Hello Interview 的系统设计版,和 Gaurav Sen 的版本互为图解补充,画环那一段看三遍就彻底通了。

一句话总结

一致性哈希用"把 key 绑在环上的位置、而不是机器序号上"这一步间接化,把"加一台机器重排九成数据"的灾难,降成了"只搬 1/N"的局部手术——这就是它能成为所有现代分布式存储"默认开启"底座的全部理由。


参考来源

  1. What is CONSISTENT HASHING and Where is it used? — Gaurav Sen — 本文解读的核心视频(约 103 万播放)
  2. Consistent Hashing | Algorithms You Should Know #1 — ByteByteGo — 418 万订阅频道的图解补充
  3. Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007) — 一致性哈希 + 虚拟节点的工业级落地
  4. Consistent Hashing with Bounded Loads — Google Research (2016) — 解决瞬时过载的官方扩展

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入