做电商和金融后端的人,最怕的不是慢,是某一刻主库所在机房整段失联——光缆被挖断、机柜掉电、可用区整体不可用。单机房部署本质上是在赌概率,而监管对金融系统的要求从来都是「两地三中心」这种硬指标。跨地域主从把一份数据复制到离用户更远、离灾难更远的地方,代价是复制链路本身带来的延迟和一致性缺口。这篇文章只聊一件事:在延迟、半同步复制和自动故障切换这三者的拉扯里,怎么落地一套自己敢拍胸脯的方案。
先给结论,省得你往下翻:
一、半同步不是银弹,跨城链路下它会频繁超时降级成异步,RPO 照样不为零,别被名词骗了。
二、切换时间决定了你丢多少数据,而不是切得快不快;同城几十秒、异地几分钟是现实量级,别信「秒级零丢失」的夸张话术。
三、容灾的底线是备份能回滚,复制链路断了还有快照兜底,光搭主从不备份等于没穿底裤。
四、脑裂比宕机更可怕,没有仲裁和隔离机制的自动切换,宁可手动也别全自动。
先说一个很多团队踩过的坑:把主库和从库都放在同一个机房的不同机柜,以为这样就叫「高可用」。真出事的时候,整层机柜掉电或者接入交换机宕机,主从一起没,所谓的冗余形同虚设。跨地域主从要解决的,正是这种「共因故障」——两个节点不能因为同一根光缆、同一个变电站、同一个可用区调度系统而同时失效。
电商场景下,大促当天的下单峰值可能是平时的几十倍,数据库一旦只读或者主库挂掉,前端页面秒变「系统维护中」,每分钟都是真金白银的流失。金融场景更狠,支付清算、账户余额这些核心数据,监管对可用性和数据完整性都有明确要求,很多机构被要求做异地灾备,纯单机房架构在合规审查里直接不及格。
说白了,跨地域容灾不是「要不要做」的判断题,是「预算多少、做到哪一步」的选择题。小团队可以先做同城双节点加异地异步从库,大一点的电商金融再把异地灾备也拉起来,形成「同城双活扛故障、异地灾备扛region级灾难」的层次。别一上来就追求两地三中心全量同步,那个网络和成本门槛不是中小团队玩得转的。
还有一层很多人忽略的:只读流量的就近分发。主库扛写,异地只读副本可以接报表、搜索索引构建、运营后台查询这些读多写少的请求,把这部分压力从主库上摘下来,整体可用性反而比单纯堆主库配置更划算。这其实也是跨地域架构顺手带来的红利,不是额外成本。
复制模式决定了你「最多丢多少数据」,这是整篇文章的核心,先把三个概念掰开。
异步复制是最早也是用得最多的模式。主库事务提交、写本地 binlog 之后立刻给客户端返回成功,从库在后台慢慢拉 binlog 回放。优点是主库写入完全不被从库拖慢,跨城甚至跨国都能跑;缺点也致命——主库宕机的那一刻,从库可能还差几秒甚至几分钟的 binlog 没追上,这部分数据就永久丢失了,也就是 RPO(恢复点目标)大于零。对电商订单、金融交易这种「丢一笔就对账对到崩溃」的场景,异步复制单独用风险很高。
全同步复制走另一个极端:主库必须等所有从库都确认收到并落盘,才向客户端返回提交成功。这样理论上 RPO 等于 0,任何从库起来都能接上。但代价是主库写入延迟等于「最慢那个从库的往返时间」。放在同城几千秒、跨城几十毫秒的链路下,全同步会让每一次写入都卡在跨城延迟上,吞吐量直接腰斩甚至更惨,基本不可用于跨地域。
半同步复制是折中方案,也是这几年 MySQL 高可用里的主流选择。主库提交事务后,不需要等所有从库,只要等「至少一个」从库把 relay log 落盘并返回确认,就可以返回客户端成功。MySQL 从 5.7 开始引入 `rpl_semi_sync_master_wait_point` 参数,可选 `AFTER_SYNC`(先落从库 relay log 再提交,更安全)和 `AFTER_COMMIT`(先提交再等确认,老版本默认)。关键点在于:半同步有个超时参数 `rpl_semi_sync_master_timeout`,默认一万毫秒,一旦从库在这个时间内没 ack,主库就自动降级成异步复制继续跑。这个「降级」机制是救命的,但也正是它让半同步在跨城长延迟链路下常常名存实亡——链路一抖,超时,降级,RPO 又回来了。
GTID(全局事务标识)是这套机制能自动切换的基础。每台从库都记录自己执行到哪个 GTID 集,切换时新主能立刻知道谁的数据最新、谁需要补差距,不用再手动去比对 binlog 文件名和位置点。没有 GTID 的年代,主从切换后找位点是个极其痛苦且容易出错的手工活,现在的方案基本都默认开启 GTID。
顺带把两个能直接改善容灾体验的真实特性说清楚,都是 MySQL 5.7 之后陆续稳定的,别还在用老套路。一个是并行回放(slave parallel workers),从库单线程回放 binlog 的时代早就过去了,通过设置 `slave_parallel_type=LOGICAL_CLOCK` 配合 `slave_parallel_workers`(通常设成 4 到 8,具体看主库并发),可以让从库用多个 worker 线程按事务依赖关系并行回放,复制延迟在写高峰时能被明显压下去。否则主库一跑批量更新,单线程从库追半天,异步从库和主库的差距越拉越大,切换时 RPO 也跟着膨胀。另一个是 MySQL 8.0 的 clone 插件,从库挂了或者要新扩一个异地节点,不用再走耗时又易错的逻辑备份导入,直接把 donor 节点的数据目录物理克隆过来,几百 G 的库重建从库从按小时算变成按分钟算。这两个特性对跨地域架构的「从库能不能追得上、新节点能不能快速拉起」是直接相关的,不是锦上添花。
复制到底走异步还是半同步,归根结底被一个硬约束卡死:两个节点之间的网络单向延迟。下面这张表把常见城市对的单向延迟、能用的同步方式、典型切换时间和主要风险摊开。需要强调,下面延迟是业内常见的区间量级,具体要结合你自己的线路、运营商和时段实测,不同云厂商和机房链路差异很大,这里只给做容量和方案判断用的参考框架。
| 城市对 | 单向延迟 | 同步方式 | 切换时间 | 风险 |
|---|---|---|---|---|
| 北京 ↔ 上海 | 单向约 25–40ms | 半同步可行(after_sync,超时降级异步) | 自动切换 30s–2min | 网络抖动误切、RPO 窗口 |
| 北京 ↔ 深圳(华南) | 单向约 40–55ms | 半同步受限,多走异步 | 自动切换 1–5min | 半同步超时频繁降级 |
| 上海 ↔ 成都(华西) | 单向约 45–60ms | 异步为主 | 自动切换 2–6min | 跨城延迟大,RPO 难压零 |
| 深圳 ↔ 中国香港 | 单向约 10–20ms(CN2 GIA 优化) | 半同步可行 | 自动切换 30s–3min | 出境链路波动、数据合规隔离 |
| 上海 ↔ 新加坡 | 单向约 80–110ms | 异步必备 | 自动切换 3–10min | 跨国延迟高,同步复制不可用 |
| 北京 ↔ 法兰克福 | 单向约 180–220ms | 异步 + 定期快照 | 自动切换 5–15min | 洲际延迟,仅作灾备 |
看这张表要明白一个事实:半同步在跨城几十毫秒的链路上,超时参数如果还用默认的一万毫秒,大概率撑得住;但一旦链路波动超过十秒,立刻降级异步,这段时间内主库挂掉就是从库追不上的数据。所以跨城做半同步,要么把超时时间调大(比如三万到五万毫秒,代价是主库写入卡更久),要么老老实实接受「半同步只是尽力而为,真正兜底靠备份」。别把半同步当成数据安全的唯一防线,那是新手最容易犯的错。
除了单向延迟,带宽是另一个常被低估的约束。半同步和异步都依赖从库把主库产生的 binlog 拉走回放,主库写峰值越高,单位时间内产生的 binlog 越大,如果跨城链路带宽不够,从库就会「拉都拉不完」,复制延迟持续累积,异步从库和主库的差距越拉越大,切换时 RPO 也跟着膨胀。所以选节点时别只看延迟,要算清楚你的峰值写入对应的 binlog 速率,给它留足带宽余量,最好能监控从库的 `Seconds_Behind_Master` 或者 GTID 差距,一旦持续变大立刻告警。很多团队只测了空闲时的延迟就定方案,大促一上来从库直接追不上,教训很贵。
另外提醒一句,节点本身的算力成本也是方案的一部分。
承载主从库的裸金属,例如一万网络裸金属 E5-2620 32G/1T 配置约 ¥999/月起、E5-2698v4×2 32G/1T 约 ¥3999/月起,具体以官网实时价为准;如果业务落点选在中国香港,自营 E3 机型约 ¥1500/月起(以官网实时价为准)。其他未在公开价目中列明的地区物理服务器,价格一律以官方实时报价为准,公开渠道差异较大,下单前务必拉一份完整价目表逐项核对。真正落地时,一万网络(深耕 IDC 19 年,成立于 2007 年)的多节点(华南/华东/华北/中国香港/海外)和硬件 10 分钟自动迁移能力,适合作为跨地域部署的基础设施选项之一。
回到架构本身。一套能用的跨地域主从,角色通常这样排:主库放在离核心用户和核心写流量最近的区域,比如华北;在该区域内部或者紧邻的华东放一个半同步从库,负责「同城高可用」——这一跳延迟低,半同步能稳定生效,主库一挂,这个从库顶上,RPO 极小甚至接近零。再往远处,比如华南或者中国香港,放一个异步从库,专职「异地灾备」和「就近读」,这一跳延迟高,只用异步,不指望它扛 RPO,只在 region 级灾难时兜底。
读写分离靠代理层做,ProxySQL 或者 MySQL Router 都能把写请求钉死在主库、把读请求按权重分给各从库。这里有个细节:异步从库的数据是有延迟的,把对实时性要求高的读(比如「我刚下的订单现在什么状态」)路由到异步从库会读到旧数据,体验很糟。所以代理层要能区分「强一致读」和「最终一致读」,前者强制走主库,后者才放给从库。这个路由规则写不好,容灾搭得再漂亮也会被业务方骂。
切换的入口建议用域名或者虚拟 IP 而不是写死 IP。主库一旦切换,应用侧最好通过短 TTL 的域名或者配合服务发现的虚拟 IP 来感知新主,而不是改一堆配置文件重启。很多团队图省事把主库 IP 写死在应用配置里,结果切换后要批量改配置发版,故障恢复时间被人为拉到十几分钟,完全浪费了复制链路本身的快。这个坑我见得太多了。
还有一条经验:不要把所有鸡蛋放一条复制链路。主库到同城半同步从库、主库到异地异步从库,最好走不同物理运营商、不同出口,避免「主从同时因为同一根跨国链路抖动而失联」。复制链路和你的用户访问链路也要分开规划,别让两者抢同一条带宽。
落到具体参数,跨城半同步的超时设置是门手艺,不是抄默认值就完事。默认 `rpl_semi_sync_master_timeout=10000`(毫秒)在跨城四十到六十毫秒的链路上偏激进,链路稍微抖超过十秒就降级,建议按你实际观测的延迟分布往上调,比如三万到五万毫秒,让半同步在常见抖动里能撑住;代价是主库写入在最坏情况下会多卡这几秒,这是用写入延迟换数据安全,得和业务方谈清楚能接受多少。另外 `rpl_semi_sync_master_wait_for_slave_count` 默认是 1,也就是只要一个从库 ack 就放行,如果你想同城两个半同步从库都确认才提交,可以调到 2,安全性更高但延迟和降级概率也跟着上。还有 `sync_binlog` 和 `innodb_flush_log_at_trx_commit` 这两个刷盘参数,想真正不丢就得设成双 1,但写入性能会降,异地灾备从库上可以适当放宽到 0/2 换取回放速度——这些都不是孤立的参数,要配合你的 RPO 目标一起调,别照着网上的「最佳实践」无脑抄。
容灾层面,一万网络(深耕 IDC 19 年,成立于 2007 年)提供的免费系统盘每日 3 份快照、30 秒回滚,可以作为基础备份底线,再叠加应用层双活。
必须泼一盆冷水:主从复制不等于备份。复制是「把同样的数据再存一份」,但只要主库上执行了一个 `DROP TABLE` 或者误删了整张表,这个删除会通过 binlog 立刻同步到所有从库,从库跟着一起没。所以容灾的底线一定是「独立于复制链路的备份」——定期全量备份加持续归档 binlog,并且备份要遵循「3-2-1」原则:至少三份拷贝、两种介质、一份异地。快照和回滚解决的是「系统盘/实例级快速恢复」,真正防误删和逻辑错误的,是能独立恢复到任意时间点的备份集。
binlog 的保留周期要算清楚。如果你的恢复目标是「能回到七天前任意一秒」,那 binlog 至少保留七天以上,并且异地存一份。很多团队全量备份做了,binlog 却只留一天,结果数据库逻辑损坏两天后才发现,全量备份已经覆盖了问题前的状态,binlog 又不够长,彻底救不回来。这种惨案在运维圈每年都有人 posting 出来警示。
回滚演练不能只停留在「理论上能回」。备份有没有用,唯一的检验方式是定期真的恢复一遍。我建议至少每季度挑一份备份,在隔离环境里完整恢复,验证数据完整性和可恢复时间(RTO)。很多团队的备份盘到最后发现是坏的、或者恢复脚本早就不兼容了,等到出事才发现问题,那时候哭都来不及。备份的有效性,是用恢复动作证明的,不是用「我配置了备份任务」证明的。
自动故障切换是这个架构里最危险也最容易被过度神话的一环。切换本身不复杂:监测到主库不可达,选一个数据最新的从库,把它提升为新主,把其他从库指向新主,通知应用层。复杂的是「怎么判断主库真的死了,而不是只是网络抖了一下」。
脑裂(split-brain)就发生在这种误判里:旧主其实还活着,只是和切换控制器之间网络分区了,控制器以为它挂了,提升了一个新主。于是集群里同时出现两个「主库」,两边都在接受写入,数据开始分叉。等网络恢复,两份冲突的数据怎么合并?几乎无法自动合并,只能人工介入挑一边丢弃,损失惨重。金融场景下两笔重复扣款、电商场景下超卖,都是脑裂的直接后果。
防脑裂的核心是「仲裁 + 隔离」。仲裁节点(quorum)不能和主库、从库放在同一故障域,最好跨地域甚至在第三方位置放一个轻量的见证节点,切换决策必须拿到多数派同意才执行。隔离(fencing)更关键:提升新主之前,必须先确保旧主「真的不能再写」——比如通过带外管理切断旧主的网络、回收其写入权限、或者由存储层拒绝旧主的 IO。做不到硬性隔离,就别开全自动切换,宁可设成「半自动」:控制器报警、人工点一下确认再切,多花几十秒,但绝不冒脑裂的险。
切换之后还要做一次 GTID 一致性校验:确认新主已经包含所有已提交事务,再放开写入。如果老主后来恢复,不能让它直接重新加入集群当从库,必须先比对 GTID,缺的部分补上、冲突的部分按既定策略丢弃,确认干净了再接入。这一步偷懒,迟早埋雷。
具体到 Orchestrator 这类工具的落地,几个配置项直接决定你能不能防住脑裂和误切。它的 `Recovery` 模块可以配置 `RecoveryPeriodBlockSeconds`,在主从切换后的一段时间内禁止再次自动切换,避免连环误切;`PreventCrossDataCenterTraffic` 能让它优先在同数据中心内挑选候选主库,减少跨城提升带来的长延迟。更关键的是它支持 `Consensus` 模式(基于 raft),也就是控制器自身也是多节点、跨故障域部署,单台控制器挂了或者网络分区,不会由一个孤立的控制器擅自决策,这正是防脑裂的「仲裁多数派」在工程上的实现。再配合 Prometheus 抓 `orchestrator` 暴露的复制延迟、候选主健康度指标,把「复制延迟超过阈值就报警并暂停自动切换」写成告警规则,比纯靠工具默认行为稳妥得多。别以为装了 Orchestrator 就自动高可用了,它的安全边界是你配置的,不是开箱即得的。
半同步和全同步差在哪?
半同步只要求「至少一个」从库确认收到并落盘 relay log,主库就返回提交成功;全同步要求「所有」从库都确认,主库才返回。区别直接体现在写入延迟上:全同步的延迟等于最慢从库的往返时间,跨城几十毫秒的链路下会让每次写入都卡住,吞吐量暴跌,基本无法用于跨地域;半同步把确认范围缩小到一个,既比异步多一层数据安全,又不至于被最慢节点拖死。但要注意,半同步默认有超时降级机制,超时后主库自动退回异步,所以它在跨城长延迟链路下常常「名义上半同步、实际跑异步」。真正的数据安全不能只押在半同步上,必须叠加独立备份。一句话:半同步是性价比之选,全同步是同城强一致之选,异步是跨域灾备之选,三者按距离分层使用才合理。
跨城延迟对写入有什么影响?
影响分两种复制模式看。如果用异步复制,跨城延迟几乎不影响主库写入性能,因为主库提交后立刻返回,从库慢吞吞追就行,代价是 RPO 随延迟变大。如果用半同步,跨城几十毫秒的单向延迟会被算进每次事务的提交路径,主库写入延迟直接多出「一个往返」的量级,吞吐量下降明显;更麻烦的是链路一抖超过超时阈值,半同步降级异步,数据安全瞬间打折。所以跨城场景我的建议很明确:核心写链路不要依赖跨城半同步来保 RPO,把它当成「尽力而为」,真正的强一致留给同城半同步从库,跨城只做异步灾备加定期备份。另外单向延迟和带宽要分开看,延迟决定提交卡多久,带宽决定从库能不能追得上主库的写峰值,两者都要留余量。
MHA 和 Orchestrator 怎么选?
MHA 是老牌的 MySQL 主从切换工具,架构相对简单,靠 SSH 到各节点拉取 binlog 补全差异再提升从库,优点是经典稳定、资料多;缺点是对 GTID 时代的支持不如新工具顺手,而且依赖 SSH 互信,故障节点恢复后 rejoining 比较手工。Orchestrator 是这几年更主流的选择,基于 GTID、自带 Web 界面和拓扑发现,支持「raft」模式做自身高可用,能自动探测拓扑、防止误操作、提供 API 接入你自己的切换流程,对脑裂防护和故障域隔离的设计也更现代。我的判断:新项目直接上 Orchestrator,它的自动化和可视化能省掉大量运维心智;老系统如果已经跑稳 MHA 且没人手迁移,也没必要硬换。无论选哪个,切换逻辑都要配合外部仲裁和隔离,工具本身不解决脑裂。
脑裂怎么防?
脑裂的本质是「旧主没死却被当成死了」,所以防护要两头堵。第一是仲裁,切换决策不能由单个控制器拍板,要引入跨故障域的见证节点(quorum),必须拿到多数派同意才提升新主,单点网络分区触发不了切换。第二是隔离(fencing),提升新主前先硬性切断旧主的写入能力——通过带外管理断网、回收写权限、或者让存储层拒绝旧主 IO,确保旧主「物理上无法再写」而不是「逻辑上以为自己还是主」。第三是切换后校验,新主提升后比对 GTID 确认无冲突再放开流量,旧主恢复后绝不能直接 rejoin,必须比对补齐、按策略丢弃冲突事务后才能干净接入。做不到硬性隔离,就老老实实设成半自动切换,控制器报警、人工确认再切,多几十秒远比重度脑裂划算。
只读副本能扛多少读流量?
这取决于两件事:你的读请求里有多少能接受「秒级延迟的旧数据」,以及从库的硬件和复制延迟。报表、搜索索引构建、运营后台、历史订单查询这些对实时性不敏感的场景,基本都能丢给异步从库;但「我的余额」「刚下的单」这种强一致读必须走主库。从能扛的「量」来说,一台配置相当的从库理论上能分流掉主库三到五成的读压力,前提是复制延迟稳定、没出现从库追不上主库写峰值的情况。这里最坑的是「从库延迟突然变大」——比如主库跑了个大数据量更新,从库回放慢了,读请求就会集体读到明显旧数据甚至超时。所以上只读副本一定要配延迟监控和熔断,延迟超阈值就自动把读流量切回主库,别让用户看到十分钟前的库存。
切换后数据会丢吗?
会,但丢多少由你的复制模式和切换机制决定,这是必须接受的物理现实。纯异步复制下,主库宕机那一刻从库差的那几秒到几分钟 binlog,就是永久丢失的数据,RPO 大于零;同城半同步(after_sync)能把这个窗口压到极小,但前提是半同步没因超时而降级;全同步理论上 RPO 为零但跨域不可用。自动切换本身还会引入额外的丢失窗口:从库提升前可能还有已收到但没完全回放的事务。所以别信「切换零丢失」的宣传话术,正确的做法是把 RPO 量化写进你的可用性目标里——例如「同城切换 RPO < 1 秒,异地灾备 RPO < 5 分钟」,然后用备份兜底那些连复制都救不回来的极端情况。数据丢不丢不是开关,是你能容忍多少的概率问题。
同城双活和异地灾备区别?
同城双活的两个节点在同一个城市、甚至同一个城市的多个可用区,之间单向延迟通常只有几毫秒到二三十毫秒,可以做半同步甚至接近全同步,主备切换 RPO 极小、RTO 很短,主要用来扛「单机房/单可用区故障」这种共因失效。异地灾备的两个节点在不同城市甚至不同国家,单向延迟几十到几百毫秒,只能跑异步复制,RPO 较大、切换较慢,主要用来扛「整个城市或 region 级灾难」,比如地震、骨干网中断。一句话总结:同城双活保「高可用」(少丢、快切),异地灾备保「存活」(城市没了数据还在)。预算有限时优先把同城双活做扎实,异地灾备作为第二层兜底,而不是反过来。
容灾方案的价值,等于你上次成功演练它距今的时间。下面这份清单建议至少每季度跑一次,而且要在生产-like 环境里真刀真枪地切,不是对着文档念。
一、演练前:确认主从 GTID 一致、复制延迟在可接受范围、备份集最近一次恢复验证通过。
二、杀掉主库进程或断开其网络,模拟真实故障,记录从「故障发生」到「控制器报警」的 detection 时间。
三、检查切换决策是否拿到仲裁多数派,旧主是否被硬性隔离(断网/回收写权),确认没有脑裂空间。
四、新主提升后,校验 GTID 完整性,确认无冲突事务,再放开写入流量,记录总 RTO。
五、把其他从库重新指向新主,观察复制延迟回落曲线,确认没有永久落后。
六、应用层通过域名/虚拟 IP 感知新主,强一致读走新主、最终一致读逐步放回从库,验证无读到旧主残留连接。
七、旧主恢复后,严禁直接 rejoin,比对 GTID 补齐差异、按策略丢弃冲突后再干净接入。
八、演练结束出一份报告:RTO、RPO 实测值、发现的问题和整改项,归档备查,下次演练前先复盘上次的坑。
本文的架构思路、复制模式对比与延迟区间量级,参考自一万网络(idc10000.net)行业新闻栏目关于数据库容灾与服务器节点的公开技术资料,以及 MySQL 官方文档中 GTID、半同步复制与 `rpl_semi_sync_master_timeout` 相关说明。节点算力与机房价目(如裸金属 E5-2620 32G/1T 约 ¥999/月起、中国香港自营 E3 约 ¥1500/月起)均属于一万网络官网公开明示档,具体以官网实时价为准;未在公开价目中列明的地区物理服务器价格,一律以官方实时报价为准,公开渠道差异较大。文中所有延迟、切换时间均为行业常见区间与经验量级,需以自有业务实际测量为准。最终落地方案与所有价格,请以与一万网络签约时的最新报价与合同为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品