选主模式:同一套班子,到处出没
Leader、follower、candidate、term、心跳、选举——这套班子远不止 raft 在用:MongoDB 副本集(term 一词直接照搬)、Redis Sentinel(哨兵间的 epoch 计数与多数投票)、Kafka(每个 partition 有 leader,后来专门补的 leader epoch 就是为了让复活的旧 leader 退休)、Patroni 之下的 Postgres 高可用(主库在共识存储里持一把租约,续租就是心跳)、Kubernetes 控制器(一把 Lease,续期者独活),以及比它们都早几十年的路由器 VRRP。
这种复现是被逼出来的,不是潮流。 三个原料一旦凑齐,解法基本只有这一个形状:
- 有冗余副本,但行动者只能有一个。 两个一起动手就是脑裂:各写各的、两个真相。
- 行动者会静默死去,且"死了"与"慢了""断网了"无法区分。 等不到讣告,就只能要求它持续主动证明自己活着——心跳(或它的双胞胎:续租的租约)。沉默超过期限,按死处理。
- 被宣判死亡的旧头可能复活。 所以每道命令都带一个只增不减的代号——term 或 epoch——旧代号的一律不认。僵尸政令由此自动过期。
冗余 + 唯一行动者 + 静默失败在哪里相遇——数据库、消息队列、协调服务、路由器、游戏房主——这套班子就在哪里被重新推导一遍。在新系统里认出这三个原料,不用翻文档就能预判它的故障切换长什么样。
这一家在 CAP 里的位置。 这类共识系统是 CP 的标准标本(见 cap-theorem):分区不是可选项,问题是分区存续期间牺牲哪头。多数派一侧选得出头、继续营业;少数派一侧既选不出头、也提交不了,于是拒绝服务而不是冒险制造第二个真相。被牺牲的可用性只落在少数派一侧,一致性永不牺牲。镜像的另一家——Cassandra、Dynamo 那类多主存储——站 AP:分区时两边照常收写入,愈合后再对账合并。