专业书籍精读 · Database Internals · 第 14 章

共识

Database Internals · Ch 14 · Alex Petrov · 2019

EN →

这一章讲什么?

你点下「转账成功」,背后不是一台机器在记账,而是三台、五台机器各记一本。这一章回答的问题很直白:这几本账,怎么保证永远是同一本?——不是「大致同步」,而是「谁也别想说出两个互相矛盾的版本」。这件事在计算机里有个专门的名字,叫共识。

先打个比方

想象五个人分散在不同城市,只能靠时好时坏的对讲机商量「周六几点聚餐」。信号会断、人会临时离席,更要命的是:你永远分不清对方是走了,还是只是信号卡住、三秒后又活过来。你们要定下一个时间,而且一旦定下,谁后来问都是同一个答案——哪怕当时有两个人根本没听见。

旧世界为什么难

最自然的办法是「选个组长,他说了算」。问题是组长失联的时候,剩下的人会同时自封组长——于是出现两个组长、两份互相矛盾的账(行话叫「脑裂」)。更尴尬的是,老组长的信号可能只是卡了一下,他自己还以为自己在位,继续往账本上写。这不是假想:真实系统里,一次垃圾回收停顿或一次网线抽风,就足够制造出两个自信满满的组长。

核心机制:两个朴素到好笑的点子

第一个点子是「过半数」。任何决定,必须有超过一半的人点头才算数。妙处在于:任何两个「过半数的小团体」,一定至少有一个共同的人——五个人里,任意两组三人必有重叠。那个重叠的人就是活档案:新的一轮一开口,他就会说「等等,上次已经定过九点了」。于是新决定永远推不翻旧决定,只能接着重复它。

第二个点子是「换届要查资历」。每次换组长都编一个届号,届号只增不减;想当新组长,必须先拿到过半数的票,而大家只投给记录不比自己少的人。这样新组长手上一定有全部已经定过的事,不会上任就把前任记下的东西抹掉。再加上「看到更大的届号就立刻退位」,老组长一发声就会被告知「你已经是上一届了」。

该怎么看它

世界上流行的做法其实只有两套讲法:一套叫 Paxos,正确但出了名难懂;一套叫 Raft,故意把同一件事讲成一本能照着做的说明书,今天的 etcd、Kubernetes、CockroachDB、新版 Kafka 都用它。诚实的代价是:每一次写都要等过半数的人点头,五台机器里一旦坏掉三台,整个系统宁可停下来不写,也不愿意写出两个版本。

一句话记住

共识不是「少数服从多数的投票」,而是一套防反悔的规矩:凡事要过半数点头,而任何两个过半数的小团体必定有人重叠,这个人记得上次的结论——所以历史只能被接着写,不能被改写。

想看 Paxos 的两个阶段、Raft 的任期与日志、拜占庭容错到底贵在哪? → 切到精读版