数据库高可用与容灾实战(9):机房级故障演练:混沌工程怎么做到可回滚
没演练过的容灾方案等于没有到这里系列已经攒齐了零件半同步、自动切换、代理改口、备份与 PITR。但零件齐不等于机器能转——机房级故障是唯一一个所有组件同时被考验、人也被考验的场景而人会掉链子预案文档半年没更新、值班同学没见过真切换、监控里最关键的那个指标恰好没接告警。混沌工程的立场很朴素与其等故障来验证架构不如自己策划一场可控的故障去验证。它的纪律性体现在两个词上实验有假设、有稳态指标、有对照组和可回滚每一枚注入的针都有对应的解毒剂且解毒动作本身也被演练过。本篇用两个模拟说明安全闸和回滚各自长什么样。机制把搞破坏做成科学方法一个合格的故障实验有六件套稳态定义用业务指标而非资源指标描述正常写成功率、P99 时延、从库延迟上界、假设“杀掉任一从库不影响写路径这类可证伪命题、注入手段网络隔离/丢包/延迟、断电拔线、CPU/IO 压满、DNS 劫持工具上 tc netem、Chaos Mesh、Blade 都能承担、爆炸半径同时受影响的节点数必须小于多数派安全线——对 5 投票节点一次最多动 1~2 台、中止条件稳态指标越线即自动停止注入并回滚而不是靠人盯屏幕、恢复验证注入撤销后系统回到稳态的实测时长。机房级演练是这套框架的大 boss 关”注入对象从进程/网络升级为整个数据中心中止条件必须升级为一组硬阈值写错误率、订单创建失败数恢复验证则要包含回切——因为真故障之后你迟早要把主写切回原机房回切本身就是一次计划内切换得建反向复制、选低峰窗口、冻结写入做对账。演练节奏上业界常见的是季度机房级 月度实例级 每周混沌自动化。每一次都必须产出数字MTTD多久发现、切换完成时刻、RTO 收敛曲线、RPO 实测值——这些数字是下一篇架构总装的需求输入。实验一没有安全闸的注入是二次事故10 台节点、每 20 秒依次注入 150 秒网络隔离集群写可用需要至少 5 个投票节点在线观察有熔断线自动刹车与没有的结局差别。N10# 参与注入的节点数GAP20# 每 20s 对下一台注入网络隔离DUR150# 每次隔离持续 150sMON10# 熔断确认窗: 异常读数需持续 10s 才落闸ABORT_AT0.01# 错误率熔断线deferror_rate(degraded):# 集群写可用需要 5 个投票节点在线: 降级数逼近/击穿多数派时错误率阶跃table{0:0.001,1:0.003,2:0.008,3:0.15,4:0.3,5:0.9}returntable[min(degraded,5)]defrun(guard):t0injected0peak0.0aborted_atNonewhilet400andinjectedN:iftinjected*GAP:injected1continuedsum(1forjinrange(injected)ift-j*GAPDUR)ererror_rate(d)peakmax(peak,er)ifguardanderABORT_AT:aborted_attMON# 读数越线后还要走完确认窗breakt5returninjected,peak,aborted_at n1,p1,_run(guardFalse)n2,p2,atrun(guardTrue)print(无熔断: 全部 %d 台被注入, 峰值错误率 %.0f%% —— 第 3 台起多数派已失守却无人踩闸%(n1,p1*100))print(有熔断: t%ds 读数越线, 确认窗 %ds 后落闸, 实际影响 %d 台, 峰值错误率 %.0f%%%(at-MON,MON,n2,p2*100))print(落闸时点 t%ds; 爆炸半径3 台 多数派安全线(还能挂 %d 台) —— 这就是实验设计四个字的含量%(at,n2,5-n2))print(安全设计: GAP(20s) 单节点恢复时间 DUR(150s) 保证读数可归因; 熔断线取业务错误率的量级下限, 而非测得出异常的安慰值)运行输出无熔断: 全部 10 台被注入, 峰值错误率 90% —— 第 3 台起多数派已失守却无人踩闸 有熔断: t40s 读数越线, 确认窗 10s 后落闸, 实际影响 3 台, 峰值错误率 15% 落闸时点 t50s; 爆炸半径3 台 多数派安全线(还能挂 2 台) —— 这就是实验设计四个字的含量 安全设计: GAP(20s) 单节点恢复时间 DUR(150s) 保证读数可归因; 熔断线取业务错误率的量级下限, 而非测得出异常的安慰值这组数字里最该抄进预案的是两条线的位置关系熔断线错误率 1%必须设在多数派失守之前确认窗10 秒远短于故障传播时间而自动刹车能把峰值从 90% 截到 15%靠的不是反应快是阈值设计得早。真实演练还要防熔断后无人收尸——落闸必须连带触发注入撤销与告警拉群演练报告里中止路径用时是和恢复用时平级的指标。实验二机房切换的 RTO大头在客户端嘴上假设机房级断电数据库侧按第 4 篇的自动化走完判定 45 秒 补账 40 秒 提升与代理改口 8 秒 93 秒。但业务真正恢复要等所有客户端改口。DNS 缓存按 TTL 收敛、连接池里的旧长连接按 maxLifetime 或报错重连收敛——两路合流成一条指数曲线。importmath T_DETECT45# 故障判定(多探测点仲裁, 第 4 篇)T_RECOVER40# 选主 补账(回放 relay binlog server 增量)T_PROMOTE8# 提升新主 代理写组改口SWITCH_ATT_DETECTT_RECOVERT_PROMOTE RTO_TARGET300.0# 业务承诺: 5 分钟内 95% 写恢复defrto(tau_dns,tau_pool,level0.95):# 切换后错指旧机房的流量按两路收敛合成: 1/tau 1/tau_dns 1/tau_pooltau1.0/(1.0/tau_dns1.0/tau_pool)need-math.log(1-level)*taureturnSWITCH_ATneed beforerto(120,300)# DNS TTL300s, 连接池 maxLifetime1800safterrto(30,60)# 专用短 TTL 域名 maxLifetime 缩短 报错立即重连print(切换完成时刻(数据库代理): t%ds%SWITCH_AT)print(现状参数 95%% 写恢复 RTO %.0fs - %s%(before,超出 300s 承诺ifbeforeRTO_TARGETelse达标))print(优化参数 95%% 写恢复 RTO %.0fs - %s%(after,达标ifafterRTO_TARGETelse仍超时))print(差额 %.0fs 全部出在客户端改口慢: 数据库侧 93s 已是硬时间, 收敛尾巴由 DNS TTL 与连接池寿命决定%(before-SWITCH_AT))forpctin(0.99,0.999):t99rto(120,300,pct)t99brto(30,60,pct)label99%ifpct0.99else99.9%print( %s 收敛: 现状 %.0fs / 优化后 %.0fs%(label,t99,t99b))print(\n回滚预案(演练必须真演练这三步):)print( 1) 实验级: 中止注入指令 - 网络恢复, 系统自愈时间 会话超时 复制重连, 实测记入报告)print( 2) 系统级: 新机房已是唯一事实源, 回切不是撤销而是二次计划切换(反向复制建立 - 低峰冻结写 - 回切))print( 3) 数据级: 切换窗口内经业务网关兜底的降级写(排队补偿单)必须对账清零, 否则 RPO 尾巴挂在演练报告上)运行输出切换完成时刻(数据库代理): t93s 现状参数 95% 写恢复 RTO 350s - 超出 300s 承诺 优化参数 95% 写恢复 RTO 153s - 达标 差额 257s 全部出在客户端改口慢: 数据库侧 93s 已是硬时间, 收敛尾巴由 DNS TTL 与连接池寿命决定 99% 收敛: 现状 488s / 优化后 185s 99.9% 收敛: 现状 685s / 优化后 231s 回滚预案(演练必须真演练这三步): 1) 实验级: 中止注入指令 - 网络恢复, 系统自愈时间 会话超时 复制重连, 实测记入报告 2) 系统级: 新机房已是唯一事实源, 回切不是撤销而是二次计划切换(反向复制建立 - 低峰冻结写 - 回切) 3) 数据级: 切换窗口内经业务网关兜底的降级写(排队补偿单)必须对账清零, 否则 RPO 尾巴挂在演练报告上350 秒对 300 秒的承诺输在哪一目了然数据库侧的 93 秒是硬成本尾巴的 257 秒全是客户端惯性。三个优化方向对应三行配置数据库专用域名把 TTL 压到 30~60 秒并保证解析器端尊重长 TTL 缓存是 DNS 容灾的经典漏洞RFC 1035 的缓存语义决定了改记录天然滞后连接池 maxLifetime 从 30 分钟降到 5 分钟让连接自然老死在可接受的改口窗口内驱动层配置连接错误立即重解析JDBC 的重连语义、代理层 keepalive 探测。演练时这四个参数都要在报告里留名——RTO 不是一个组件的属性是整条调用链的参数乘积。常见陷阱与演练清单演练只在能看监控的时间段做真实故障不挑时间至少一次演练安排在无人值守窗口周末夜间 值班新人验证告警链是否真的叫醒人。注入手段不验证撤销通道先确认撤销指令 100% 能执行再开始注入——撤销失败时你手里要有第二把闸直接恢复网络/电源的人工 runbook。把切换成功当终点没有回切演练的容灾是单向门原机房修复后的回切窗口、反向复制的延迟与数据核对都要进同一份演练方案。稳态指标用 CPU/连接数这些是体检指标不是心跳指标熔断线要挂在业务成功率上。演练报告只写通过必须写数字——MTTD、切换用时、RTO 收敛曲线、RPO 实测、中止路径触发次数否则下一次演练没有改进靶子。演练把纸面架构锤成了实测数字。最后一篇回到工程原点把这些数字、参数与组件收拢成一张可评审的架构答卷——下一篇也是本篇终章《数据库高可用与容灾实战10架构实战为一个 500GB 生产库设计高可用方案》。参考来源Principles of Chaoshttps://principlesofchaos.org/WikipediaChaos engineeringhttps://en.wikipedia.org/wiki/Chaos_engineeringGitHubNetflix/chaosmonkeyhttps://github.com/Netflix/chaosmonkeyGitHubchaos-mesh/chaos-meshhttps://github.com/chaos-mesh/chaos-meshRFC 1035Domain names - implementation and specificationhttps://datatracker.ietf.org/doc/html/rfc1035本系列已结集为免费专栏数据库高可用与容灾实战从主从复制到机房级演练进阶推荐付费专栏Python 自动化接单实战从脚本到第一单限时 ¥9.9首篇免费试读