冗余是保证系统和数据高可用最常用的手段:服务多副本、数据多备份,挂了能切、丢了能找。从同一机房的 HA 集群,到同城/异地灾备,再到同城/异地多活,差别主要在「备机是否接流量」和「机房之间有多远」。
本篇把这几种形态摊开对比,说明数据冗余的同步/异步差异,点出异地多活面临的一致性挑战,并给出一份实用的选型建议——光有冗余不够,还必须配合自动故障转移,才能真正缩短不可用时间。
TL;DR
- 服务冗余 = 同一服务多份部署,挂了切到备份;数据冗余 = 同一数据多份备份,提高安全性。
- HA 集群强调服务多副本,不强调地域;同城/异地灾备与多活才把冗余拉到机房/城市维度。
- 灾备 vs 多活:灾备备机不接流量;多活所有站点同时对外服务,资源利用率更高。
- 同城 vs 异地:核心差别是机房距离;异地多活主要应对火灾、地震等大范围灾害。
- RTO / RPO 驱动选型:RTO(恢复时间目标)和 RPO(恢复点目标)是选择灾备形态最重要的业务指标,先量化再选型,不要把最复杂的方案当默认答案。
- 异地多活的代价:异步复制引入延迟,需要解决写冲突、会话黏性、CAP 取舍等难题;工程复杂度极高,不达临界规模不要轻易上马。
- 冗余必须配故障转移:不可用服务要能自动切到可用服务,无需人工介入;同时要防范脑裂与误切换震荡。
- 常见例子:Redis Sentinel 主挂 slave 升主;Nginx + Keepalived 用 VIP 做透明切换。
- 切换陷阱:脑裂、健康检查误判与 VIP 震荡是自动故障转移的高频坑——靠仲裁 / fencing、合理阈值与切换冷静期来防。
Table of contents
Open Table of contents
1. 服务冗余与数据冗余
冗余设计是保证系统和数据高可用最常用的手段,核心思路分两条线:
- 服务冗余:相同的服务部署多份。正在使用的实例挂掉时,系统可快速切换到备份实例,大幅缩短不可用时间。
- 数据冗余:相同的数据保存多份。单份数据损坏或丢失时,可从副本恢复,提高数据安全性。
两条线缺一不可:只做服务冗余,数据损坏时无处可恢复;只做数据冗余,服务宕机时仍需等待人工介入,实际 RTO 变成”何时有人看到告警”。
2. RTO 与 RPO:量化容灾目标
在选择冗余形态之前,必须明确两个业务指标:
- RTO(Recovery Time Objective,恢复时间目标):故障发生到服务恢复可接受的最长时间。RTO = 5 分钟,意味着系统需要在 5 分钟内完成切换;RTO = 1 小时,则允许人工介入手动恢复。
- RPO(Recovery Point Objective,恢复点目标):故障发生时,可以接受多久以前的数据丢失。RPO = 0 意味着不允许任何数据丢失;RPO = 1 小时,意味着接受最多 1 小时内写入的数据在故障时无法恢复。
| 冗余形态 | 典型 RTO | 典型 RPO | 实现复杂度 |
|---|---|---|---|
| HA 集群 | 秒级 | 接近 0 | 低 |
| 同城灾备 | 分钟 ~ 小时 | 分钟级(依赖备份频率) | 中 |
| 异地灾备 | 小时级 | 分钟 ~ 小时级 | 中 |
| 同城多活 | 秒级 | 接近 0 | 高 |
| 异地多活 | 秒级 | 接近 0(强一致代价极大) | 极高 |
RTO/RPO 越苛刻,对应的冗余方案越复杂、成本越高。 这张表的作用是让决策有据可依——先清楚业务对”最长恢复时间”和”最大数据损失”的容忍度,再倒推合适的架构,而不是默认追求最高等级。
3. 从 HA 集群到同城 / 异地多活
高可用集群、同城/异地灾备与多活是冗余思想在高可用系统设计中最典型的应用,核心差异在于地域跨度和备机是否承载生产流量。
| 形态 | 地域 | 备机是否接流量 | 主要防护目标 |
|---|---|---|---|
| HA 集群 | 同机房 | 是(多实例均分) | 单节点故障 |
| 同城灾备 | 同城不同机房 | 否 | 机房级故障(断电、火灾) |
| 异地灾备 | 不同城市/国家 | 否 | 城市级灾难 |
| 同城多活 | 同城不同机房 | 是 | 机房级故障 + 提升并发 |
| 异地多活 | 不同城市/国家 | 是 | 城市级灾难 + 提升全球可用性 |
各形态简要说明:
- 高可用集群:同一服务部署两份或多份,某实例挂掉后可切换到其他实例。强调服务多副本,不要求地域分散。
- 同城灾备:主服务部署在一个机房,备服务部署在同城另一机房,但备机不接生产流量。可规避单机房断电、火灾等意外。
- 异地灾备:与同城灾备类似,但机房跨度更大(通常跨城市甚至跨国),备机同样不接流量。用于应对区域性灾难。
- 同城多活:同城不同机房均接流量,资源利用率高于灾备,同时具备机房级容灾能力。同城机房间往返延迟通常 ≤2ms,数据同步与读写路由的复杂度远低于异地。
- 异地多活:将服务部署在地理位置不同的多个机房,所有站点同时对外服务。用于应对火灾、地震等大范围灾害,同时可就近为全球用户提供服务。
从 HA 集群到异地多活:地域跨度变大,备机是否接流量决定是灾备还是多活。
一句话:HA 集群是服务冗余;同城/异地灾备与多活才是地域冗余。 多活相对灾备的关键变化是:所有站点同时对外服务,资源利用率更高,但数据一致性挑战也更大。
3.1 同城多活与异地多活的选型边界
对于大多数互联网业务,同城多活已经可以应对主要的机房级故障(断网、断电、硬件损坏),且延迟可控,数据同步相对简单。
优先考虑同城多活的场景:业务对延迟敏感、数据量大导致异地同步成本高、监管要求数据不得出境、团队容灾演练资源有限。同城多活的工程复杂度明显低于异地,是大多数中等规模平台性价比最高的选择。完成同城多活并跑通切换演练,已经能将可用性推到 99.99% 量级。
必须上异地多活的场景:城市级灾难风险不可接受(金融核心系统、政务平台、超大型 C 端产品);或需要在多个大洲服务用户、必须就近接入以降低跨洋延迟。异地多活的工程复杂度比同城多活高出不止一个数量级,不到业务规模和合规要求达到临界点,建议不要轻易上马——很多公司在没有足够工程能力支撑的情况下强上异地多活,反而因为方案不完善引入了新的不可用风险。
3.2 异地多活的一致性挑战
异地多活面临的最大技术难题是数据一致性:不同机房距离远,网络往返延迟通常在 30~100ms 以上,强一致(两阶段提交)会让每次写入都付出巨大延迟代价,因此生产环境几乎都选择异步复制。异步复制引入以下挑战:
- 复制延迟(Replication Lag):从库数据可能落后主库数秒甚至更长。若流量切换到从站,用户可能读到旧数据。常见缓解手段是”读主写主”的强一致路由,以及对写操作做本地确认后再异步广播。
- 写冲突(Write Conflict):多活意味着多个站点同时可写。如果两地用户同时修改同一条记录,数据库层必须有冲突检测与解决策略——常见手段包括 Last-Write-Wins(以时间戳为准,存在数据丢失风险)、版本向量(适合文档型数据)、业务层合并(最准确但最复杂)。很多异地多活方案采用”按用户/按地域分片写入”来规避跨地冲突,即每个用户的写操作固定路由到某一个主机房,从而在逻辑上消除热点写冲突。
- 会话黏性(Session Stickiness):一次会话内的请求必须路由到同一个站点,否则用户在站点 A 写了数据、下一个请求路由到站点 B 却读到旧值。通常用一致性哈希或 UID 哈希把同一用户的请求固定到同一机房。
- CAP 取舍:异步复制意味着系统在分区容错(P)的前提下选了可用性(A)而非强一致性(C)。这个取舍必须在设计阶段明确告知业务方,并制定数据修复预案——当检测到数据不一致时,如何以哪份数据为权威来源进行修复。
异地多活架构实施复杂度极高,需要解决跨地域网络延迟、数据同步一致性、流量路由策略等一系列难题,详见数据中心选型。
3.3 异地多活的流量路由
异地多活中,流量路由决策直接影响数据一致性和延迟:
按地域分片(Geo-Sharding):中国用户路由到国内机房,海外用户路由到海外机房,就近服务降低延迟。跨地域数据访问(如中国用户访问海外用户的数据)通过一次跨机房请求处理。适合用户分布有明显地理规律的全球化产品。
主机房写、从机房读:写操作始终路由到主机房,读操作就近路由到最近机房(可能读到略滞后的数据)。一致性比多活弱一点,但冲突完全消除,实现相对简单。适合对写一致性要求高、对读延迟有就近需求的场景。
4. 数据冗余:同步、异步与 Quorum
数据冗余并非只有一种形态,同步/异步复制与 Quorum 机制各有适用场景:
同步复制(Synchronous Replication):写操作必须等所有副本(或至少 N 个副本)确认后才返回成功。数据一致性最强,RPO ≈ 0;但写延迟会累加到最慢副本的延迟,且任意副本不可用都会阻塞写入,可用性相对较低。适合金融核心账务等对数据零丢失有强要求的场景。
异步复制(Asynchronous Replication):主节点写成功即返回,副本在后台异步同步。写延迟低、可用性高;但副本可能落后主节点,主节点宕机时有少量数据丢失风险(RPO > 0)。适合对延迟敏感、可容忍短暂数据滞后的场景,是大多数互联网业务数据库的默认选择。MySQL 半同步复制是一个折中方案:至少等待 1 个从库确认后再返回,在延迟和安全之间取平衡。
用数字把 RPO 落到实处:假设订单服务写入 QPS 为 800,主备机房网络往返(RTT)8ms(同城)。同步复制下每次写入多等 1 个 RTT,写延迟 +8ms,RPO = 0——只要备库确认成功再返回给客户端,主库故障也不会丢数据。换成异步复制,主库写成功立即返回,备库通常滞后 50~200ms(取决于网络与备库负载);一旦主库毫无预警地宕机,丢失的数据量 ≈ 滞后时间 × QPS,即 100ms × 800 QPS ≈ 80 条记录的 RPO 风险敞口。同城场景下这个窗口一般能压在百毫秒级;异地场景 RTT 常到 100~200ms,若仍用异步复制,滞后可能被拉到秒级,RPO 风险敞口随之放大一个数量级——这正是异地多活比同城多活更难解决数据一致性的根本原因(见 §3.2)。
把这个估算写成代码,方便在容量评估时直接套:
# 异步复制的 RPO 风险敞口:主库无预警宕机时,滞后窗口内尚未复制的写入量
def rpo_exposure(write_qps, replica_lag_ms):
return write_qps * replica_lag_ms / 1000 # 约等于「可能丢失的写入条数」
rpo_exposure(800, 100) # 同城:800 QPS × 0.1s ≈ 80 条
rpo_exposure(800, 2000) # 异地:滞后拉到 2s ≈ 1600 条,敞口放大一个数量级
结论很直接:异步复制的 RPO 敞口 = QPS × 复制滞后。要压低敞口只有两条路——降低滞后(更快的网络、更轻的备库负载)或提高复制等级(半同步 / 同步),而后者的代价是写延迟与可用性。
Quorum(法定多数):在 N 个副本中,写操作需要至少 W 个副本确认,读操作需要至少 R 个副本响应,只要 W + R > N 就能保证读到最新数据。典型参数:N=3,W=2,R=2。Quorum 是 Cassandra、etcd 等分布式存储的基础;它在可用性和一致性之间找到了一个可调节的平衡点——减小 W 则写更快但一致性弱,减小 R 则读更快但可能读到旧值。Raft/Paxos 本质上也是基于多数派决策的 Quorum 协议,只是在日志复制上加了更严格的顺序约束。
W/R/N 的取舍可以直接用一行判据算清楚:
# W + R > N 才能保证「读到的至少一个副本包含最新写」;容错数 = N - max(W, R)
def strong_read(n, w, r):
return w + r > n
strong_read(3, 2, 2) # True:读写各 2,容忍 1 节点故障,最常用
strong_read(3, 1, 3) # True:写快(W=1),但读要 3 个全在线,读可用性差
strong_read(3, 3, 1) # True:读快(R=1),但写要 3 个全在线,写可用性差
strong_read(3, 1, 1) # False:1+1 ≤ 3,读可能落在没写到的副本上 → 读到旧值
同一个 N,把「一致性预算」在 W 和 R 之间怎么分,取决于业务是读多还是写多;只要守住 W + R > N,就能在可用性和一致性之间自由滑动。
一句话:同步复制保数据,异步复制保延迟,Quorum 可按需调节。大多数系统把”跨城容灾”配异步复制、“本地高可用”配同步或 Quorum,把风险降到可接受范围。
行业参考——Kafka 的 ISR 机制:Kafka 用 ISR(In-Sync Replicas) 实现了一种实用的 Quorum 变体。每个 Partition 的所有副本中,只有与 Leader 落差在阈值内的副本才属于 ISR。写入时只需等待 ISR 中的所有副本确认(通过 min.insync.replicas 配置最小 ISR 数)。副本落后时自动移出 ISR,恢复同步后重新加入——动态维护”有效多数”而非静态等待固定节点,在保证持久性的同时兼顾了可用性。这与传统 Quorum 的核心思想一致,但工程实现更贴合流式场景。
MySQL 半同步复制也是一个常见的折中方案:主库写入后,至少等待 1 个从库确认收到 binlog(而非执行完成)再返回。相比全同步延迟更低,相比纯异步安全性更高,是大多数互联网公司在单机房内保障数据不丢的默认选择。关键参数如下:
-- 主库:启用半同步,至少 N 个从库确认 binlog 后再向客户端返回成功
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1; -- 需确认的从库数(想更安全就调大)
SET GLOBAL rpl_semi_sync_master_timeout = 1000; -- 1s 内无从库确认则退化为异步,保住可用性
SET GLOBAL rpl_semi_sync_master_wait_point = AFTER_SYNC; -- 从库落盘后主库再提交,切换时不丢已确认事务
-- 从库:启用半同步接收端
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
两个参数值得特别注意:wait_point = AFTER_SYNC(MySQL 5.7+ 默认)保证「从库先落盘、主库后提交」,是切换不丢已确认事务的关键;而 timeout 是一把双刃剑——它在从库全部卡住时自动退化为异步以保住写可用性,但退化的那一瞬间 RPO 就从 ≈0 变回了「异步敞口」,因此退化必须打告警,否则你以为的半同步早已悄悄变成了异步。
4.1 备份、热备与副本
“数据冗余”在不同语境下有三种实现形态,理解它们的区别有助于根据 RPO 需求选择合适的方案:
备份(Backup):定期将数据快照写到另一个存储介质(磁带、对象存储)。数据只有在备份时刻存在副本,备份间隔越长 RPO 越大(如每天备份则 RPO 最长 24 小时)。用于抵御数据损坏、误删等”数据层灾难”,而非应对服务不可用——恢复需要从备份中还原,RTO 通常以小时计。
热备(Hot Standby):备机实时接收主机的写操作(同步或异步复制),始终处于”准备好随时切换”的状态,但平时不接流量。与备份的区别是数据实时性:热备 RPO 接近 0,备份 RPO 取决于备份频率。Redis Sentinel 模式下的 Slave 就是热备典型实现。
副本/多主(Replicas / Multi-Primary):多个节点同时保有数据的实时副本,且通常都可以接流量(多活)。代价是需要处理副本间的一致性问题(见 §3.2)。Kafka Partition 的 ISR 副本集是这种模式在消息队列领域的典型实现。
5. 故障转移(Failover)
光做好冗余还不够,必须配合**故障转移(Failover)**才能真正缩短不可用时间。所谓故障转移,是指不可用服务快速且自动切换到可用服务,整个过程不需要人工干预。
Redis Sentinel 示例:哨兵模式下,Sentinel 进程持续监测 master 节点健康状态。一旦检测到 master 故障,Sentinel 集群通过投票自动将某一台 slave 提升为新 master,并通知客户端更新连接目标,整个过程无需人工介入。
# sentinel.conf —— 关键项
# 需要 2 个哨兵同意才判定 master 客观下线(quorum),防止单哨兵误判
sentinel monitor mymaster 10.0.0.11 6379 2
# master 连续 5s 无响应即判定主观下线
sentinel down-after-milliseconds mymaster 5000
# 切换后同一时刻只允许 1 个 slave 从新 master 同步,避免全部 slave 一起拉库拖垮它
sentinel parallel-syncs mymaster 1
# 一次故障转移的整体超时
sentinel failover-timeout mymaster 15000
quorum 必须小于等于哨兵总数且建议为「过半」(如 3 哨兵配 2),这是防脑裂的第一道闸:只有超半数哨兵都认为 master 挂了才会触发切换。
Nginx + Keepalived 示例:Keepalived 通过 VRRP 协议为一组 Nginx 节点绑定一个虚拟 IP(VIP)。主节点宕机后,备用节点在秒级内接管 VIP,客户端连接不中断,切换过程对外透明。
# keepalived.conf —— MASTER 节点
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100 # BACKUP 设为 90,优先级高者持有 VIP
advert_int 1
authentication { auth_type PASS auth_pass 1111 }
virtual_ipaddress { 10.0.0.100/24 }
# 关键:探测 Nginx 进程本身,而非只看机器存活,避免"机器活着但 Nginx 挂了"仍持有 VIP
track_script { chk_nginx }
}
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh" # pgrep nginx,失败则降权
interval 2
weight -20 # 检查失败时 priority-20,触发 VIP 漂移到 BACKUP
}
track_script 是最容易被漏配的一项:不检查业务进程只看机器心跳,会出现「机器还在、Nginx 已挂,但 VIP 死守在故障节点」的假高可用。
冗余要配自动切换:Sentinel 升主、Keepalived 切 VIP,都是故障转移。
5.1 故障转移的常见陷阱
自动故障转移在实践中有几个高频踩坑点:
脑裂(Split-Brain):主备节点之间的心跳链路出现故障,但两者与外部的网络连接仍然正常。备节点误判主节点宕机,提升自己为主——此时两台机器都认为自己是主,同时接受写操作,数据双写冲突。解决方案是引入仲裁机制:Redis Sentinel 要求多哨兵投票(超半数同意才切主),etcd 依赖 Raft Leader 选举确保任意时刻只有一个合法主节点;或配置 STONITH(Shoot The Other Node In The Head)在网络隔离时强制关闭对方节点,防止双主并存。
健康检查误判(False Positive):网络抖动或机器短暂过载导致健康检查超时,触发不必要的故障转移——而原主节点并没有真正宕机。频繁误切换会导致系统震荡,且每次切换都有秒级短暂不可用。缓解手段:设定合理的超时与连续失败次数阈值(如连续 3 次心跳超时才触发切换),并执行多层探测(TCP 连接 + 业务层 /health 接口响应)而非单一指标;同时对切换事件打告警,异常频率可反映健康检查阈值是否需要调整。
VIP 漂移震荡(VIP Flap):Keepalived 场景下,若主备之间的链路不稳定,VIP 可能在主备之间反复漂移,导致客户端频繁重连、业务抖动。需要对切换设置冷静期(debounce),切换后一段时间内不允许再次切回,并监控 VIP 切换频率作为健康信号。
集群容错策略(Failover / Failback / Failsafe / Failfast)的详细说明见依赖韧性。
6. 选型决策
面对五种冗余形态,以下思路可帮助快速定位适合的方案:
第一步:确定 RTO 和 RPO 要求。
- RTO 可容忍分钟级以上 + RPO 可容忍分钟级 → 灾备(同城或异地),成本最低,实现相对简单。
- RTO < 5 分钟 + RPO 接近 0 → 必须上多活(同城或异地)。
第二步:评估灾难防护级别。
- 只防单机、单机架故障 → HA 集群已足够。
- 防单机房故障(断电、火灾、机房网络中断)→ 同城灾备或同城多活。
- 防城市级灾难(地震、大面积断网)→ 异地灾备或异地多活。
第三步:评估团队能力和成本。 异地多活的工程成本是同城多活的数倍:跨城数据同步、冲突解决、流量路由调度、全链路压测、混沌工程演练缺一不可。若团队规模和预算不支撑,优先把同城多活做扎实,再规划异地。同城多活做到位的系统已经能挡住 95% 以上的故障场景。
第四步:分阶段演进,不要一步跳到最复杂形态。 先做好本机房的 HA 集群 → 扩展到同城多活 → 视需求升级到异地多活。每个阶段配套容灾演练(定期模拟主节点宕机、机房断网),确保切换流程真正可用而不只是纸上方案。
6.1 容灾演练:纸面方案不等于可用
选型建议落地后,定期容灾演练是检验方案真正有效的唯一手段。推荐的演练层次:
1. 单节点故障演练(每月一次):随机 kill 一个服务实例,观察流量是否在 1 分钟内完成切换,告警是否正常触发。这是最基础的演练,应该成为常规运维动作而非”特殊事件”。
2. 数据库主节点故障演练(每季度一次):手动触发主节点宕机(或使用 Chaos Engineering 工具),验证自动切换流程:从库提升为主库的时间、客户端重新路由的时间、数据是否一致。每次演练后记录实际 RTO,与目标 RTO 对比。
3. 机房级切换演练(每半年一次,适用于同城/异地多活):将一个机房的流量完全切走,观察另一机房是否能承载全量流量,切换过程中的错误率和延迟是否在 SLO 范围内。这是验证多活方案真实有效性的关键测试。
演练的最大价值不在于”演练通过了”,而在于每次演练都会发现新问题——DNS TTL 没配好、客户端重试逻辑有 Bug、切换后某个本地缓存没有失效、告警通知路径失效等。建立演练问题跟踪,把每次暴露的问题都修复,可用性才会真正提升。
7. 反模式
“反模式”不只是”做错了”,更多是”看起来像做了但实际没用”:
- 有冗余没健康检查:备机部署了,但没有持续探活机制,故障时需人工发现并手动切换,RTO 变成”何时有人看到告警”——这不是高可用,只是备份。
- 异地多活没有冲突解决策略:只做了数据双向同步,没有定义写冲突时以哪份数据为准——一旦两地同时写入相同记录,数据将以不可预测方式覆盖,且难以事后修复。
- 健康检查过于激进:间隔 100ms、超时 200ms,网络稍有抖动就触发切换,系统在正常运行时频繁震荡,引入比它解决的问题更多的不可用时间。
- 把 RPO = 0 视为默认目标:强同步复制的代价是写延迟上升和可用性下降(任一副本不可用都会阻塞写入),并非所有业务都需要零数据丢失——先量化可以接受多大的数据丢失窗口,再决定复制策略。
- 容灾只在纸上,从不演练:文档化的切换流程 ≠ 可执行的切换流程。建议每半年至少做一次真实的故障切换演练,才能暴露实际问题(DNS TTL 未配置、客户端重连逻辑有 Bug、切换后数据不一致等)。
- 把备份等同于高可用:定时备份解决的是”数据被误删或损坏后能恢复”,不能解决”服务宕机后快速恢复可用”。备份 RPO 通常以小时计,不能用来支撑”秒级 RTO”的高可用承诺。
关于”灾备等级 SLA 的常见误解”:很多团队以为”我们做了主备,所以可用性是 99.99%“——但 99.99% 意味着全年停机不超过 52 分钟,这要求从故障发生到完全恢复(包括告警触发、自动切换、流量恢复)的全程在分钟内完成。如果切换需要人工操作,光是值班人员响应就可能要 5~10 分钟。真正的可用性等级需要通过实际演练测出来,而不是根据架构推算出来。
另一个常见误解是将”RTO”与”告警响应时间”混淆:告警响应是发现故障所需时间,RTO 是从故障发生(而非从发现)到完全恢复的时间。如果你的告警需要 5 分钟才能触达值班人员,再加上切换操作的 2 分钟,实际 RTO 是 7 分钟——即使你的自动切换本身只要 30 秒。
8. 组件级 HA 速览
通用冗余形态之外,常见中间件有各自的高可用落地方式,选型时不要混用术语:
| 组件 | 常见 HA 形态 | 要点 |
|---|---|---|
| MySQL | 主从 / 半同步 / MGR / 云多 AZ | 关注复制延迟与切换后的只读窗口;金融账务优先半同步或强同步 |
| Redis | Sentinel(主从+哨兵)/ Cluster | Sentinel 解决主挂切换;Cluster 解决容量与分片,两者问题不同 |
| Kafka | 多副本 + ISR + min.insync.replicas | 可用性与持久性由副本与 ISR 共同决定,详见 Kafka 可靠性篇 |
| Nginx / LB | Keepalived VIP / 云多实例 ALB | LB 自身不能成为单点,见负载均衡 |
一句话:先问「挂了谁顶、数据丢不丢、切换要多久」,再选组件的 HA 模式——不要把「开了集群」当成「已经高可用」。
小结
- 冗余 = 服务多副本 + 数据多备份,两者缺一不可。
- RTO / RPO 是选型的起点:先量化业务对恢复时间和数据丢失的容忍度,再倒推冗余形态;不要把最复杂的方案当默认答案。
- 灾备强调”能切换”,多活强调”常态下都在跑”;同城多活是大多数平台性价比最高的选择,异地多活应在工程能力充足后再上马。
- 异地多活的一致性挑战(异步延迟、写冲突、会话黏性、CAP 取舍)需在设计阶段就明确应对方案。
- 冗余必须配故障转移,自动化是关键;同时要防止脑裂、误判和 VIP 震荡等切换陷阱。
- 定期演练是冗余真正生效的保障——每次演练都会暴露你在文档里看不到的问题。
延伸阅读:集群容错策略(Failover / Failback / Failsafe / Failfast)与舱壁隔离见依赖韧性;机房布局与 SG+VA 双活选型见数据中心选型;切换与降级预案的验证见混沌工程。