知识卡片

高可用状态决策的三种方式及其固有缺陷

结构图卡

内容

无论是计算高可用还是存储高可用,都要先解决同一个基础问题:系统怎么判断当前状态是正常还是异常,判断错了,后面的任何补救行动都没有意义。但这里存在一个本质矛盾:恰恰是靠冗余实现的高可用系统,状态决策本身不可能做到完全正确,三种常见决策方式各自的缺陷都源于这个矛盾。独裁式决策由一个独立的”决策者”收集所有冗余节点上报的信息、统一做判断,好处是不会出现决策混乱(只有一个声音),但决策者本身就成了新的单点——它自己故障时整个系统就失去了准确判断状态的能力,而如果给决策者本身也搞一套高可用状态决策,就陷入了”由谁来判断这个判断者是否正常”的递归死循环。协商式决策靠两个独立个体交换信息后按规则决策,最常见的形式是主备决策:两台机器都从备机启动,建立连接、交换状态,某一台被推举为主机、另一台继续做备机。这套架构简单,难点全在”信息交换出问题”这一刻怎么办——如果主备之间的连接中断,备机要不要认为主机已经故障:认为故障就升级为主机,但主机其实没坏,系统就凭空多出两个主机;不认为故障就继续当备机,但如果主机这次真的坏了,系统就彻底没有主机了。加更多条连接(双连接、三连接)能降低误判概率,但降不到零,还会引入新问题——多条连接传回的信息不一致时该信谁的,这本身也是无解的。民主式决策靠多个独立个体投票、按”多数取胜”确定状态(如ZooKeeper选主用的Paxos算法),比协商式更复杂难懂,还有一个协商式没有的固有缺陷:脑裂——当集群因为连接中断被分割成两个互相看不见对方的子集群时,每个子集群会各自独立选出一个主节点,导致系统同时存在两个主节点、状态陷入混乱。应对脑裂的常规做法是要求”参与投票的节点数必须超过系统总节点数的一半”,未达到半数的子集群不进行选举——这确实能防止脑裂,但代价是降低了整体可用性:如果真的是过半节点故障(而非网络分区导致的脑裂),系统同样会因为凑不够半数投票节点而选不出主节点,即使剩下的少数节点本身完全健康,系统也等同于宕机了。三种方式没有一种能在所有场景下都不出问题,选哪种本身也是一个需要结合具体业务权衡的复杂判断。

结构图

flowchart TB
  Q["状态决策的三种方式"]
  Q --> A["独裁式<br/>单一决策者收集信息统一判断<br/>⚠️决策者本身是单点,故障时整个决策失效"]
  Q --> B["协商式(如主备)<br/>两方交换信息按规则决策<br/>⚠️连接中断时:升级判故障可能变2主,<br/>不升级判正常可能变0主"]
  Q --> C["民主式(如ZooKeeper Paxos)<br/>多方投票,多数取胜<br/>⚠️算法复杂 + 固有的脑裂缺陷"]
  C --> D["脑裂:集群分割成两个互不通信的子集群<br/>各自选出主节点→系统出现2个主节点"]
  D --> E["应对:投票节点数须过半才能选举<br/>解决脑裂,但真实过半节点故障时<br/>系统也会因凑不够票数而'宕机'"]

参考来源

- 位置:《从零开始学架构》第05讲《复杂度来源:高可用》"高可用状态决策"(源文件:_epub-src/OEBPS/text00000.html) - 结论依据:原文说明"通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确",并分别分析独裁式"当决策者本身故障时,整个系统就无法实现准确的状态决策"、协商式"如果备机在连接中断的情况下认为主机故障……系统就出现了两个主机……如果不认为主机故障……系统就没有主机了"、民主式"脑裂……原来统一的集群因为连接中断,造成了两个独立分隔的子集群,每个子集群单独进行选举,于是选出了2个主机……为了解决脑裂问题,民主式决策的系统一般都采用'投票节点数必须超过系统总节点数一半'规则……这种方式虽然解决了脑裂问题,但同时降低了系统整体的可用性",直接支撑本卡片结论。 - 原始内容:通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确……脑裂的根本原因是,原来统一的集群因为连接中断,造成了两个独立分隔的子集群,每个子集群单独进行选举,于是选出了 2 个主机……为了解决脑裂问题,民主式决策的系统一般都采用"投票节点数必须超过系统总节点数一半"规则来处理……这种方式虽然解决了脑裂问题,但同时降低了系统整体的可用性。