ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

征信系统同城双活改造:从单机房到99.95%高可用架构实践

征信系统同城双活改造:从单机房到99.95%高可用架构实践 把征信系统从单机房架构搬到同城双活是我这几年看过的所有高可用改造里最值得拆开聊的一个。ADVANCE.AI 在印尼的征信服务 CBI 最近完成了同城双活部署对外公布可用性达到 99.95%也是业内第一家把征信业务真正跑成同城双活的团队。两个机房同时对外提供服务任何一边发生故障另一边都能直接把流量接住业务几乎无感知。这篇不写公关稿把同城双活的设计思路、落地路径和真正容易翻车的细节讲清楚。不管你是做基础设施、SRE、数据库还是金融业务架构后面这些内容应该都有参考价值。1. 征信系统到底在慌什么1.1 一笔征信查询背后还有多少件事征信系统不是简单的“查一下用户数据”。以 CBI 这类征信服务为例一次查询通常要经过用户授权校验、机构身份校验、数据源匹配、数据聚合、风控评分、结果加密返回等多个环节。每个环节都可能依赖不同的下游系统比如黑名单库、还款流水、设备信息、第三方数据源。任何一个环节超时整笔查询就可能失败。如果征信查询不可用银行、消费金融、电商平台的风控链路就会整体卡住业务不是慢几分钟而是直接停摆。用红绿灯来类比普通系统出故障像路灯坏一盏还能走征信出故障像整个路口红绿灯全灭所有方向都堵死。所以征信是最不能接受“不可用”的金融基础设施之一这也是 ADVANCE.AI 在印尼把 CBI 做成同城双活的核心动力。1.2 99.95%的可用性是什么概念可用性通常用“多少个九”来衡量99.95% 意味着一年内不可用时间不超过 262.8 分钟也就是 4.38 小时。拆到季度每个季度最多停产约 65 分钟拆到月度每月最多只有 21.9 分钟。一次机房故障只要处理慢一点当月指标就没了。为了更直观可以和 99.9%、99.99% 放在一起看可用性年停机时间月均停机时间适合场景99.9%8.76 小时43.8 分钟一般互联网业务99.95%4.38 小时21.9 分钟金融核心链路99.99%52.6 分钟4.4 分钟极强一致与高价值交易从 99.9% 到 99.95%表面只提升了 0.05 个百分点但停机窗口几乎砍了一半。越往后每提升一点点对架构、运维、组织响应的要求都是指数级上升。99.95% 是一个相对聪明的平衡点也是这次 CBI 同城双活选择把目标定在这条线的原因。1.3 同城双活解决的是哪一类故障单机房最容易翻车的故障其实不是软件 bug而是物理环境。机房断电、空调故障、光缆被施工挖断、交换机升级出问题这些事在机房没有绝对免疫能力。传统灾备架构里平时备机房只同步数据、不承担流量遇到故障要“发现-确认-切换-拉起-核对”少说也要几十分钟数据还可能丢。同城双活的思路完全不同备机房在平时就承担读写流量两个机房都在对外服务故障发生时负载调度层直接把流量从坏机房挪到好机房不需要先拉起一堆应用。CBI 选择同城而不是异地本质是为了保数据一致性。同一座城市内拉两套机房网络时延能控制在毫秒级数据同步延迟才压得下去。如果两个机房隔着一两千公里延迟几十毫秒很多强一致场景就没法做。所以“同城双活”解决的是单机房不可用但不允许数据丢失、不允许长时间切换的这一类故障。2. 同城双活架构设计的四个关键决策2.1 两个机房之间的距离和专线怎么选同城双活的第一步是选址。两个机房最好在同一个城市但绝对不能离得太近否则一场区域性的电力或网络故障可能把两个机房一起带走也不能太远太远时延受不了。我见过比较合理的规划是同一城市不同区域距离 20 到 50 公里之间。机房之间用两条物理隔离的专线做互联一条主用一条备用避免“一根光缆断了双活直接变成单活”。专线的带宽要按业务峰值估算不能按平均流量算。因为故障切换时一个机房的流量在短时间内会全部压到另一个机房如果带宽只有平时的 80%切换后就会丢包或拥塞。除了带宽还要重点看专线的丢包率和抖动这个在后面的踩坑部分会具体说。总之网络选型和建设是双活的地基这一步省了后面一切免谈。2.2 应用层先要做到无状态应用层做双活之前必须先解决“状态”的问题。无状态的意思是同一个用户的任意请求落到哪个机房都能处理不依赖某台机器上的本地内存、临时文件或者会话。最常见的改造是把用户会话从本地移到 Redis 或集中式缓存把文件从本地磁盘移到对象存储或者做双向挂载的共享存储本地日志只留短时间完整日志走远程采集。如果不做这一步故障切换后用户请求被路由到另一个机房但那个机房不认识这个 session用户会发现登录态失效、流程中断数据写到一半下一跳找不到上下文只能报错。所以双活改造的第一优先级永远不是数据库而是把应用层洗成一个可水平扩展、可随机路由的无状态池。说句实话这一步虽然枯燥但性价比最高。2.3 数据双活是最大的硬骨头应用无状态之后真正的难点集中在数据层。征信数据不允许丢也不允许两个机房写出来的数据不一致。这里常见的有两条路一是利用数据库本身的主主同步比如 MySQL 主主复制两个机房各部署一套互相把 binlog 同步给对方二是直接换分布式数据库比如 TiDB、OceanBase 这类天生支持多活、多副本一致性的产品让数据库自己去处理节点状态。对已经跑了很多年的存量系统来说直接重构到分布式数据库的成本和风险都很大所以不少团队会先选 MySQL 主主同步过渡。主主同步要处理自增主键冲突最简单的做法是让两个机房的自增步长不同比如机房 A 用奇数主键机房 B 用偶数主键。同时要开启半同步复制尽量保证主库事务提交时至少有一个从库已经把日志接住。下面这个表能比较好地看出两种方案的取舍方案优势风险适用情况MySQL 主主同步改造轻团队熟悉脑裂风险、冲突处理复杂存量系统、紧急双活分布式数据库数据一致性内建迁移成本高、SQL 兼容性风险新系统或愿意重写征信服务如果追求数据绝对一致建议优先评估分布式数据库如果实在没时间MySQL 主主同步也得把仲裁和冲突检测做扎实。2.4 RPO 和 RTO 怎么定聊可用性指标离不开两个词RPO 和 RTO。RPO 是灾难发生时最多能丢多少数据RTO 是多久能把业务恢复起来。对 CBI 这类征信服务合理的口径是 RPO 尽量做到秒钟级甚至零丢失RTO 控制在 5 分钟以内。要说明一下RPO 和 RTO 不是直接换算成可用性 99.95% 的但它们是支撑这个可用性数字的两根柱子。如果一次故障导致 6 分钟不可用且没有丢数据全年可用性就守不住 99.95%。所以在设计时要把目标倒推成能力要求故障发生时负载调度必须在若干秒内完成摘流应用无状态化要保证摘流后立即可以接管数据层同步延迟必须在安全阈值内。建议从业务侧拿一份“不可用损失清单”把每一次宕机的损失量化这样定 RPO、RTO 的时候不会拍脑袋也不会被一句“不能丢数据”逼到成本失控。3. 落地路径从单活到双活不是一步到位3.1 先做只读双活再打开写入口同城双活的落地最好别搞“大爆炸式”切换而是分阶段推进。第一阶段把第二个机房部署成一个真正的只读副本让查询和只读报表流量先双活分流这个阶段不做写入数据库同步还是主从模式风险很小。第二阶段选一两个对一致性要求相对低的业务模块打开写入口比如配置管理、用户资料更新这类非核心链路观察双向同步是否稳定。第三阶段核心征信查询和评分链路的写流量才切过去数据库主主同步全部打开此时才算是真正的读写双活。为什么一定要按这个顺序因为每一阶段都有明确的可观测信号同步延迟是否正常、冲突是否出现、回滚是否顺利都能在小范围内验证。如果一上来就全量读写双活出了脑裂或者数据冲突排查范围是全局的基本等于事故扩大化。3.2 流量入口如何按权重分发双活的流量入口一般由 GSLB 或者专线负载均衡来负责在 DNS 解析层或四层负载上把同一个域名按权重分发到两个机房的入口 IP。默认权重我建议从 80/20 开始慢慢调整到 50/50不要第一天就完全对半分。权重可以在线调整但要注意会话保持同一个用户的一串操作尽量落在同一个机房避免每次都跨机房访问。另外一个容易被忽略的细节负载调度系统本身要独立于两个机房部署。如果调度器只放在机房 A机房 A 挂掉你连切换流量的操作都做不了双活直接失去意义。所以 GSLB 最好做成三节点两个机房各一个再加一个第三方仲裁点。这个细节看起来小实际故障时能救你一命。3.3 数据库同步参数和延迟治理数据库双活的成败很大程度取决于同步延迟。以常见的 MySQL 半同步复制为例需要开启半同步插件并设置合理的超时时间。超时设置太短主库在等待从库确认的过程中直接退化成异步复制数据可能丢太长主库写性能会被拖垮。生产环境一般从 3 秒开始压测找到适合业务的平衡点。可以参考下面的 SQL-- 开启半同步复制MySQL 5.7 及以上示例 INSTALL PLUGIN rpl_semi_sync_master SONAME semisync_master.so; INSTALL PLUGIN rpl_semi_sync_slave SONAME semisync_slave.so; SET GLOBAL rpl_semi_sync_master_enabled 1; SET GLOBAL rpl_semi_sync_slave_enabled 1; SET GLOBAL rpl_semi_sync_master_timeout 3000;不同版本参数名和默认值有差异要以实际版本文档为准。开启半同步之后还要关注并行复制参数比如从库的并行 worker 数量。如果主库写入并发很高从库单线程回放跟不上延迟会持续累积。建议对同步延迟做秒级监控延迟超过 5 秒就报警超过 30 秒必须考虑手动断开写入防止备机房在故障切换时读到明显旧的数据。3.4 上线前的堡垒式回滚方案任何一次双活切换身边都要留一张“回滚板”。所谓堡垒式回滚就是提前定义清楚什么情况下必须放弃双活状态、回到单机房并且把回滚动作做成可一键执行的脚本。常见回滚条件有三个机房间同步延迟超过 500 毫秒且持续不回落数据校验不一致的记录超过预设阈值业务错误率明显上升并且根因指向双活链路。回滚入口建议不要做成全自动必须人工确认。原因是回滚本身也有风险如果是因为流量突增而不是故障回滚可能把压力全部压回原机房造成更大的雪崩。我在项目里最怕的不是“切不过去”而是负责人举棋不定。所以回滚方案里要写明谁有决策权、回滚前需要看哪三个指标、回滚后由谁验证。这些白纸黑字写下来比任何架构图都管用。4. 故障切换与演练实录4.1 值班要盯的六个指标双活系统上线之后监控指标不是越多越好。我通常建议值班看板只放六个核心指标业务请求成功率、数据库同步延迟、机房间专线时延与丢包率、核心服务心跳、API 响应时长 P99、消息队列积压量。其他指标可以放在二级页面避免告警疲劳。这里有个很关键的原则告警只发“需要人行动”的事件能自动恢复的抖动事件只记录、不打搅。这六个指标之间往往有因果关系比如专线丢包率突然升高随之而来的是同步延迟变大业务成功率下降。值班人员看到的是“同步延迟高”但要能顺着链路往下查先看专线、再看主库负载、最后看从库回放。所以监控看板建议按链路组织而不是按系统组织。4.2 模拟机房断电的演练步骤演练是双活系统真正的验收。我经历过最有效的一次演练是模拟一个机房整体断电先通知所有相关方进入演练窗口然后记录当前同步延迟和数据校验基线接下来通过脚本把数据库写入流量强制导向另一个机房再彻底摘除目标机房的入口流量制造一种“这个机房已经不接受新连接”的状态。之后观察另一个机房的业务成功率、响应时延、数据同步是否追平整个过程尽量控制在 10 分钟以内。演练结束后恢复原机房不要立即切回流量先让数据追平再做一次全量数据校验再逐步恢复权重。演练频率建议至少每季度一次遇到大版本升级或者机房网络改造还要加一次专项演练。每次演练都得输出一份复盘记录“哪个环节决策不够快、哪个监控没提前看到、谁负责的确认动作延迟了”。4.3 自动切换还是人工仲裁同城双活要不要全自动切换是很多团队纠结的点。对征信系统我的建议是“自动检测、人工确认、脚本执行”简称半自动。全自动的风险在于误判一次误切换带来的麻烦往往比故障本身还大。半自动的做法是让监控系统自动捕捉异常并计算可信度但最终切换动作由一个值班负责人点击确认。判断逻辑要尽量简单可以参考下面的伪代码思路def health_check(zone): if zone.api_error_rate ERROR_RATE_THRESHOLD: return unhealthy if zone.sync_delay SYNC_DELAY_THRESHOLD: return unhealthy return healthy def failover_decision(): zone_a health_check(zone_a) zone_b health_check(zone_b) if zone_a unhealthy and zone_b healthy: notify_oncall(A异常建议切换至B) elif zone_b unhealthy and zone_a healthy: notify_oncall(B异常建议切换至A) else: notify_oncall(状态异常请人工介入暂不自动切换)生产环境要比这段复杂很多比如要加仲裁节点、要处理两个机房都异常的情况但核心逻辑就是这样宁可多喊人不要自作主张。4.4 回切比切换更危险很多团队把精力放在“切过去”结果栽在“切回来”。故障恢复后原机房应用启动数据库开始追平数据这时候如果立刻把流量切回去原机房可能因为数据滞后读到的还是旧数据连接池刚建立服务能力也没回暖大流量压过来很容易再次宕机。回切必须走一条比故障切换更保守的路径先验证数据追平到目标位点再做关键链路冒烟测试然后按 10%、30%、50%、100% 分步导流每步观察 5 到 10 分钟。如果回切过程中任何一个机房错误率回升就要停在当前比例先排查再继续。记住一句话故障切换是逃生回切是搬家搬家要比逃生更小心。5. 踩过的坑和排查技巧5.1 专线时延低但抖动一样要命第一个坑来自网络质量。我们曾经在测试环境看到两个机房专线的平均时延只有 1 毫秒以为稳了结果跑双活压测时数据库同步每隔几分钟就断一次。排查到最后发现问题不在带宽而在抖动专线表面时延低但每过一段时间就出现连续丢包导致半同步复制超时、同步连接反复重建。从那以后我要求任何双活项目在选专线时不仅要测平均时延还要测 99 分位时延、丢包率和连续丢包时长。网络稳定性比单纯的低时延重要得多。这一条也是我建议值班监控必放“丢包率”的原因很多人只盯时延漏掉了真正的元凶。5.2 脑裂不是运气问题是设计问题双活最容易出现的事故叫脑裂简单说就是机房间网络断了两边都认为对方挂了于是都开始接受写请求等网络恢复后数据怎么都合不到一起最后只能手工挑数据损失惨重。脑裂的根治办法不是靠运维反应快而是靠机制仲裁节点必须存在。例如部署三个仲裁角色两个机房各一个再加一个独立节点规定只有拿到多数派同意的一方才能继续接受写入数据库层还可以用 fencing 机制在确认本机接管前主动把故障节点的资源隔离掉防止它继续写。这些东西听起来重但在征信数据这种高价值场景里是必须的。我的建议是脑裂方案在一开始就要画进架构图而不是等出了问题再补。5.3 业务方不配合双活就是空中楼阁双活不是纯技术团队自己能扛下来的事业务方的配合非常关键。每次请求要支持幂等重试不会产生重复数据超时时间不能设得太大否则故障切换时一个请求挂几十秒前端早就超时了查询失败要有明确的降级策略比如返回“请求繁忙”还是返回旧快照。这些都不是 DBA 或 SRE 能替代业务决定的。我见过最难受的情况是运维把所有切换动作练熟了结果业务方告诉你说我们所有接口都不支持幂等重试就等于重复扣款。所以双活项目一定要从一开始就拉业务方进虚拟团队把幂等改造、超时设置、降级预案拆成具体任务排进迭代而不是上线前才问业务方“你准备好了吗”。5.4 监控报警的“狼来了”效应最后一个坑是监控报警设计。很多团队上线双活后因为阈值设得太敏感一晚上告警几十次值班人第二天就麻木了真正的高危告警反而被忽略。我踩过一次就是因为值班人习惯了“同步延迟高”的告警等到真出问题时以为是常态导致故障处理慢了十几分钟。后续调整成金字塔式报警最低层只记录不打扰中间层发到值班群但不强制处理最高层才打电话或者强通知。同时把“自动恢复事件”和“需要人处理的事件”分开前者用于事后统计后者才触发告警。高可用性系统从来不是靠堆告警堆出来的而是靠设计上的冗余、机制上的托底、和流程上的可执行。如果让我说说这次 CBI 同城双活项目留给我的最大印象不是那套漂亮的架构图也不是 99.95% 这个数字而是整个团队愿意把每一个假故障当成真故障来对待。我自己做过的高可用改造里凡是能长期守住可用性指标的都是因为有一个可观测、敢切换、能回滚的闭环。征信这条链路上每一秒的不可用都可能被放大成业务损失所以同城双活不是炫技是金融业务发展到一定规模后的必答题。希望这篇文章能让你少走一些弯路。
返回列表