计算机网络:什么是网络分区?
结论:网络分区(network partition)指集群节点本身都活着,但彼此网络不通,集群被切成若干互不可见的孤岛。 它和"节点宕机"在监控上几乎无法区分——两者都表现为心跳超时,所以分布式系统必须假设分区一定会发生。
1. 分区长什么样
机房 A 机房 B
+------------------+ +----------------+
| node1 node2 | X | node3 |
| node4(3 票) | 链路中断 | (1 票) |
+------------------+ +----------------+
多数派 少数派
仍可选举、可写 凑不够 quorum,拒绝写
典型成因:机房专线中断、交换机故障、云厂商可用区(AZ)网络抖动、安全组误配、BGP 路由泄漏。 分区还可能是单向的(A 能到 B,B 回不来),也可能只切断部分节点,形态比"一刀切"复杂得多。
2. 为什么危险:脑裂
两侧都自认为主,就会出现双写:
| 角色 | 正常时 | 分区后(无仲裁) | 分区后(多数派仲裁) |
|---|---|---|---|
| 主节点 | 唯一,接收写 | 两侧各有一个"主" | 只有多数派侧有主 |
| 写请求 | 全部成功 | 双写,数据分叉 | 少数派侧直接失败 |
| 恢复后 | 无冲突 | 人工合并或丢弃数据 | 少数派回放日志追平 |
双写的代价往往不是"丢一点数据",而是自增 ID 冲突、库存超卖、账户出现两个版本的余额, 恢复时无法自动判定谁对。
3. 工程上的三道防线
- 多数派(quorum):任何决策需要过半数节点同意。5 节点可容忍 2 台故障,3 节点只能容忍 1 台。
- 租约(lease):主节点持有时限租约,续不上就主动降级,避免"自认为还是主"。
- 隔离(fencing):用 fencing token 或 STONITH 强制旧主停服,防止它恢复后继续写。
etcd 的典型参数:
# /etc/etcd/etcd.conf.yml 片段
heartbeat-interval: 100 # 毫秒,主节点心跳间隔
election-timeout: 1000 # 毫秒,从节点多久没收到心跳就发起选举
# election-timeout 要明显大于网络 RTT 抖动,经验值是 heartbeat 的 10 倍左右
# 查看成员健康与任期,判断是否发生过切主
etcdctl endpoint status --cluster -w table
etcdctl endpoint health --cluster
RAFT TERM 明显增长、LEADER 发生变化,往往就是分区或网络抖动留下的痕迹。
4. 常见追问
Q:分区和宕机怎么区分? 单看心跳分不出来。要靠旁证:节点自身监控正常但互相 ping 不通、多个节点同时失联、跨 AZ 流量异常。 工程上不追求精确区分,而是让系统在两种情况下都安全。
Q:CAP 里为什么 P 必须接受? 分区是网络固有属性,不是设计选项。能选的只有分区期间"拒绝服务保一致(CP)"还是"继续服务容忍不一致(AP)"。 CA 只在"永不分区"的假设下成立,所以严格说 CAP 是三选二。
Q:超时时间是不是越小越好? 不是。太小会把网络抖动误判为故障,频繁切主,每次切主都伴随短暂不可用,抖动还会被放大。 跨 AZ 的选举超时通常在几百毫秒到数秒,且要压测验证,不能照抄。
Q:Redis 主从在分区时会怎样?
异步复制下,旧主在少数派侧仍接受写入,恢复后这部分数据会被新主覆盖,即"分区期间写入丢失"。
min-replicas-to-write 能让旧主在从库不足时拒绝写,缓解但不能根除。
Q:怎么降低分区概率? 把 quorum 成员分散到不同 AZ / 机架,避免同一台交换机下凑齐多数;跨城链路做双路冗余; 监控专线质量而不只是端口的 up / down 状态。
Q:为什么分区恢复后不能直接合并? 两侧的写可能互相冲突(同一主键被改成不同值、自增序列重复)。 要么按业务规则做冲突消解(如 LWW、版本向量),要么在检测到分区时就让少数派停止写入,从源头上避免分叉。
小结
网络分区是"活着但联系不上",杀伤力在于让每个节点基于不完整的信息做决定。 应对思路只有一条:任何可能产生两个主的决策,都必须经过多数派同意,并能在事后隔离旧主。 超时、租约、fencing token 这些看似琐碎的机制,本质上都在为这条原则兜底。