Quorum 机制
Aug 2, 2021 21:00 · 1102 words · 3 minute read
问题
在分布式系统中,普遍使用多副本来提升服务的可用性,通过将操作复制到集群中的其他服务器来实现,这样能够确保在进程崩溃后,处理的结果依然可以由其他进程来提供给客户端。那么问题来了:需要多少服务器来确认该复制,原始服务器能够放心大胆地确认该更新已经被集群完全认可了呢?当然等待所有的服务器都确认是最安全的,但是整体反应就会变得非常慢,跟实时就不沾边了;另一方面如果没有足够的副本,那么更新是有可能丢失的——安全性就打折扣了。关键在于在系统的性能和安全性之间要取得平衡。
解决方案
当集群中的大多数节点确认了更新,集群就提交这把更新。我们把这个数字称为 quorum。所以如果我们的集群有 5 个节点,就需要 3 个代表~。(n 个节点的集群,quorum 为 n/2 + 1)
换个角度 quorum 也表明了集群可以容忍多少个节点故障——就是集群的节点总数减去 quorum。所以 5 个节点的集群能够容忍其中两个节点故障。综上所述,如果我们想要集群容忍 f 个节点故障,那集群要有 2f + 1 个节点。
下面是几个需要 quorum 的典型案例:
- 更新集群中服务器的数据:高水位线被用于确保只有数据确保在大多数服务器上可用时才对客户端可见。
- 选主:在 Leader-Followers 模式中,只有在得到大多数服务器的投票后才能当选 leader。
确定集群中服务器的数量
只有当大多数服务器正常运行,集群才能发挥作用。在复制数据(data replication)的系统中,有两点要考虑:
-
写操作的吞吐量
每次向集群写数据,都需要被复制到多个服务器上。每多一台服务器都会增加完成这次写入的开销。写数据的延迟和构成 quorum 的服务器数量成正比。将集群中节点的数量翻倍会把集群的吞吐量降低到原来的一半。
-
要容忍的故障节点数量
能够容忍多少台服务器故障取决于集群的规模。但是只向集群添加一台服务器并丕定带来更强的容错:向一个三节点的集群添加一台服务器毛用没有。
考虑到以上两点,大多数基于 quorum 的生产系统只有三到五个节点。一个五节点的集群能够容忍两台服务器故障,并且可以达到每秒处理几千个写请求的数据吞吐量。
下面的例子说明如何根据容错数量和对吞吐量的影响来选择服务器数量。吞吐列展示了相对吞吐量,以强调吞吐量和服务器数量是成反比的。这个数字会因系统而异。读者请参考发布在 Raft 理论 和 Zookeeper 论文 的实际吞吐量数据。
服务器数量 | quorum | 容错数量 | 相对吞吐能力 |
---|---|---|---|
1 | 1 | 0 | 100 |
2 | 2 | 0 | 85 |
3 | 2 | 1 | 82 |
4 | 3 | 1 | 57 |
5 | 3 | 2 | 48 |
6 | 4 | 2 | 41 |
7 | 4 | 3 | 36 |
案例
- 所有像 Zab、Raft、Paxos 之流的一致性实现全都是基于 quorum 机制。
- 那些本身不实现一致性的系统,甚至会使用 quorum 机制来确保在发生故障或网络分区时,至少有一台服务器可以获得最近的更新。比如 Cassandra 数据库,数据库更新可以被配置为只有在大多数服务器成功更新记录后才返回成功。