菲律宾支付系统灾备与高可用怎么设计?多通道冗余、故障切换与演练清单(2026)
我在马尼拉负责一个本地生活电商平台的技术团队,支付这块接了 GCash、Maya 和 QRPH。去年台风季我们连吃了两次大亏:一次是某钱包侧深夜维护延长,我们的收银台整整一个小时只有失败页;另一次是机房所在区域断电,下单服务活着,但回调入口不可达,用户付了钱、系统却不知道。两次事故之后我们把支付系统按"灾备与高可用"重新设计了一遍,这篇文章就是那次重构的方法论:怎么画故障面、多通道冗余有哪几种做法、什么时候该切、切完怎么回来、平时怎么演练。单笔交易失败后的自动换通道属于另一个话题,见智能路由与级联支付怎么设计,这里讲的是"一条路长时间不通"时整个系统怎么活下来。
在菲律宾,支付不可用是常态,不是意外
先接受一个事实:菲律宾的支付链路比国内脆弱得多。钱包侧有定期维护窗口,有时会延长;QRPH 涉及多家参与机构,任何一家的清算系统维护都可能影响一部分用户,影响范围怎么判断在QRPH 系统维护期间商户收款怎么办里写过;台风和停电会让区域网络整体抖动;电信运营商的移动网络质量不稳,用户端 App 唤起失败也会被当成"支付挂了"。
所以我们设计时把"收不到钱"拆成两类。第一类是用户付不出去,表现为下单失败或收银台打不开,损失的是这段时间的订单。第二类是用户付了但我们不知道,表现为回调丢失、反查超时,损失的是用户信任和客服成本,而且会在事后对账时制造大量差异。第二类更危险,因为它是静默的。高可用设计的目标不是"永不故障",而是让第一类故障的窗口尽量短、让第二类故障不发生。
先画清楚故障面:四层各自会怎么坏
我们把整条链路分成四层,对每一层问三个问题:坏了的表现是什么、我们怎么第一时间知道、谁有权做切换。
- 通道层:GCash、Maya、QRPH 参与机构、银行转账网络。表现为某一种支付方式的成功率骤降或全部超时。知道的方式是按支付方式分开统计的成功计数和钱包方公告。
- 网关层:你接入的聚合网关或持牌网关的 API。表现为下单接口报错、回调停止、查询接口超时。知道的方式是主动探测加被动指标。
- 自身系统层:下单服务、订单库、消息队列、回调入口、定时任务。表现为服务不可用或处理积压。知道的方式是常规的应用监控。
- 网络与基础设施层:云区域、DNS、TLS 证书、出口 IP 白名单。表现为"一切代码都对但就是连不上"。这层最容易被忽略,证书过期和白名单 IP 变更是两个高频原因。
画完这张图你会发现,"多通道冗余"只解决通道层和网关层的问题,后两层要靠自己的架构。很多团队签了三家服务商,结果数据库单点一挂全部白搭。
多通道冗余的三种形态
所谓多通道冗余,是指同一种支付方式有不止一条可用路径。具体怎么组织,我们比较过三种形态:
| 形态 | 做法 | 优点 | 代价 | 适合谁 |
|---|---|---|---|---|
| 主备切换 | 同一支付方式接两条路径,平时只走主路径,主路径熔断后切到备路径 | 实现简单,对账只在切换期间变复杂 | 备路径长期无流量,切换时有"冷启动"风险 | 订单量中等、技术团队较小的商户 |
| 双活分流 | 两条路径同时承接流量,按订单尾号或商户号分配 | 切换无感,两条路径都被持续验证 | 两套对账、两套结算,成本与复杂度都高 | 订单量大、对可用性要求高的平台 |
| 按场景分层 | App 内走钱包直连,线下走 QRPH,大额走银行转账,每个场景的备选是"换一种支付方式" | 贴近用户实际行为,故障时引导成本低 | 需要前端配合做支付方式的动态展示 | 线上线下都有、支付方式多样的商户 |
我们最终用的是"主备切换 + 按场景分层"的组合:每种支付方式有一条主路径和一条备路径,同时在收银台层面允许故障时把用户引导到另一种支付方式。双活分流我们试过一个季度,对账成本让财务同事明确反对,后来撤了。
健康探测与熔断:什么时候切、谁来决定
切换的前提是"知道坏了"。我们用三类信号互相印证:
- 主动探测:定时请求网关的健康接口或一个只读的查询接口,只看能否在限定时间内返回合法响应。
- 被动指标:按支付方式和路径分开统计的下单成功计数、失败计数、回调到达延迟。注意用滑动窗口内的计数而不是比例做阈值,夜间低流量时比例会被几笔失败放大。
- 外部信号:网关状态页、钱包方公告、同行群里的消息。这类信号用来确认,不用来触发。
主动探测的脚本很朴素,关键是超时要短、结果要落盘、连续失败要能被别的组件读到:
#!/usr/bin/env bash
# 每分钟对主/备两条网关路径各探测一次,只看"能否在限定时间内返回合法响应"
for name in primary backup; do
url=$(grep "^$name=" /etc/pay/gateways.conf | cut -d= -f2)
code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 2 --max-time 5 \
-H "Authorization: Bearer $PROBE_TOKEN" "$url/v1/health")
echo "$(date +%s) $name $code" >> /var/log/pay/probe.log
if [ "$code" != "200" ]; then
redis-cli INCR "probe:fail:$name" >/dev/null
redis-cli EXPIRE "probe:fail:$name" 300 >/dev/null
else
redis-cli DEL "probe:fail:$name" >/dev/null
fi
done
探测结果和被动指标一起喂给熔断器。熔断器是经典的三态:关闭(正常走主路径)、打开(全部走备路径)、半开(放少量请求试探主路径)。下面是我们下单服务里的实现骨架,阈值全部用整数计数:
// 以整数计数做熔断,避免小样本下按比例误判
const state = { primary: { fails: 0, openedAt: 0, status: 'closed' } };
const FAIL_LIMIT = 5; // 连续失败达到阈值即打开熔断
const OPEN_MS = 120000; // 打开后等待两分钟再进入半开试探
function pickGateway() {
const p = state.primary;
if (p.status === 'open' && Date.now() - p.openedAt > OPEN_MS) p.status = 'half-open';
return p.status === 'open' ? 'backup' : 'primary';
}
async function createOrder(order) {
const gw = pickGateway();
try {
const res = await gateways[gw].create(order); // 两条路径实现同一个内部接口
if (gw === 'primary') { state.primary.fails = 0; state.primary.status = 'closed'; }
await db.orders.update(order.id, { gateway: gw, gatewayRef: res.ref });
return res;
} catch (err) {
if (gw === 'primary') {
const p = state.primary;
p.fails += 1;
if (p.fails >= FAIL_LIMIT || p.status === 'half-open') {
p.status = 'open'; p.openedAt = Date.now();
notifyOncall('primary gateway circuit opened');
}
return createOrder(order); // 同一订单号重试,靠幂等键防止重复下单
}
throw err;
}
}
决策权的原则是:自动只允许往下切,切回主路径要人工确认。自动切回容易在主路径半好不坏时来回抖动,每抖一次对账就多一堆跨路径的订单。半开状态只用来收集证据,真正关闭熔断由值班同事在看过成功计数之后手动执行。
自身系统的高可用:别让冗余止步于通道
通道冗余做完,下面这些自身系统的事情同样决定你能不能扛住故障:
- 下单幂等:商户订单号做唯一键,重试和切换路径都用同一个订单号,网关侧也以它去重。高并发下的限流与排队在支付网关 API 限流与并发处理里有专门讨论。
- 回调入口与业务处理解耦:回调先落队列、立即应答,再由消费者处理。入口只做验签和入队两件事,这样即使业务库慢了,回调也不会被判定为投递失败。
- 回调可重放:所有原始回调报文落盘保留,出事后能按时间段重放。接收、幂等与补偿的设计见GCash 支付 Webhook 重试机制怎么设计。
- 定时反查兜底:对创建后超过一定时间仍是待支付的订单,逐个用查询接口反查。这是对抗"用户付了但我们不知道"的最后一道防线,任何回调链路故障都靠它收尾。
- 数据层:订单库主从同步、跨可用区备份、定期恢复演练;队列持久化;密钥与路由配置多副本存放且不依赖单一配置中心。
- 出口与证书:网关白名单登记两个以上出口 IP;证书到期前的告警至少提前一个月;DNS 用两家解析商。
降级策略:通道全挂时还能不能收钱
冗余解决"换条路",降级解决"路全断了怎么办"。我们的降级阶梯分四级,按顺序触发:
- 切备路径:上面的熔断器自动完成,用户无感。
- 切支付方式:收银台隐藏故障的支付方式,引导到可用的方式,例如钱包直连不可用时展示 QRPH 静态码或银行转账。
- 延迟支付:允许用户先锁定订单与库存,系统生成支付链接,恢复后通过短信或站内信推送,做法参考Payment Link 支付链接在菲律宾怎么用;线下场景还可以引导到便利店柜台代收,见菲律宾 OTC 线下代收渠道是什么。
- 人工登记:极端情况下由客服手工登记收款凭证,事后统一补录和对账。这一级必须有权限控制和审计日志。
每一级的前端文案、订单保留时长、库存释放规则都要提前定好并写进代码,事故当晚临时商量是来不及的。
灾备演练与 runbook:每季度演一次
没演练过的灾备方案等于没有。我们每季度做一次演练,场景从下面这张表里轮换,每次至少两个:
| 故障场景 | 注入方式 | 期望行为 | 验收标准 |
|---|---|---|---|
| 主路径下单超时 | 在出口网关对主路径域名注入延迟 | 熔断打开,流量切到备路径,告警送达值班 | 切换在阈值内完成,期间无重复订单 |
| 回调全部丢失 | 临时关闭回调入口的入站规则 | 反查兜底在设定时间内补齐所有已支付订单 | 对账差异为空 |
| 订单库主库宕机 | 停掉主库实例 | 从库提升为主,下单服务自动重连 | 切换期间失败的请求可被用户重试且不产生脏数据 |
| 网关密钥泄露 | 按应急流程轮换密钥 | 新密钥在所有实例生效,旧密钥失效 | 轮换期间下单与验签无失败 |
| 云区域级断网 | 在非高峰时段切断主区域出口 | 流量切到备区域,数据从备份恢复 | 恢复点与恢复时间在事先定义的目标内 |
每个场景对应一份 runbook,内容固定为六项:触发条件、切换命令或开关、通知名单、观察指标、回切条件、复盘模板。runbook 放在团队都能访问且不依赖故障系统的地方。演练先在沙箱环境跑通,再在生产用小流量时段做,沙箱环境的用法见支付网关沙盒测试环境怎么用。
持牌网关在冗余架构里的位置
说到多通道冗余,常见的误区是"多签几家服务商就安全了"。每多一家,你就多一套对账文件、多一条资金路径、多一份合规尽调、多一组密钥要管。我们的做法是:选一家持牌网关做主路径,它内部已经对接了多家钱包和清算通道并做了路由冗余;再保留一条独立的备路径,只覆盖核心支付方式。这样商户侧只需要做"网关级"备援,而不是自己去管每一条钱包通道。
SMARTPAY 持有菲律宾央行(BSP)颁发的 OPS 与 EMI 资质,GCash、Maya、QRPH 等通道在网关内部做了多路由与故障切换,商户通过同一套 API 接入,资金由持牌机构归集和结算。把它作为主路径时,商户自己的冗余工作可以集中在回调兜底、数据层和降级策略上。
选主路径时,除了看可用性承诺,更要核实对方的持牌状态和资金托管方式,方法见菲律宾支付服务商合规怎么核查;持牌主体和非持牌代理在故障时的处置能力差别很大,这一点在菲律宾持牌支付网关怎么选里有展开。
常见问题
小商户也需要做多通道冗余吗?
需要,但可以简化。最低配置是:一条主路径加一种可切换的支付方式(比如 QRPH 静态码),加上定时反查兜底。真正的大头是反查和幂等,而不是多签服务商。
主备切换会不会让同一笔订单被收两次?
做对幂等就不会。同一订单号在两条路径上只允许一条成功,切换前的待支付单要么在原路径上过期关闭,要么在反查确认状态后再决定是否在备路径重建。切换期间的订单要打标记,方便事后对账。
备路径平时没有流量,怎么保证它是活的?
两种办法:一是把一小部分固定流量常年放在备路径上,比如某个尾号段的订单;二是每天用真实的小额交易做一次端到端验证并自动退款。我们选的是前者,顺带把备路径的对账也养成了日常。
回调丢失和通道故障怎么区分?
看反查。回调没来但反查显示已支付,是回调链路问题;反查也超时或报错,是通道或网关问题。两者的处置完全不同,前者补单,后者切路径。
多路径之后对账怎么做?
订单表记录每笔走的是哪条路径和对应的网关参考号,对账时按路径分别拉取通道侧明细再合并。三方核对的技术方案见菲律宾支付对账系统怎么搭建。
云服务商区域故障时支付系统怎么办?
把支付核心服务部署在两个区域,数据跨区同步,DNS 或负载均衡做区域级切换。代价不小,是否值得取决于你的订单量和停机损失,但至少备份和恢复演练是必须的。
多久演练一次合适?
我们是每季度一次全流程演练,外加每次大版本上线前做一次熔断与回切的小演练。频率低于半年,runbook 就会和实际系统脱节。
写在最后
回头看那两次事故,真正救我们的不是多签了一家服务商,而是后来补上的反查兜底、回调重放和写在代码里的降级阶梯。多通道冗余是必要的,但它只是四层故障面里的两层。把故障面画清楚、把切换权限定清楚、把演练变成例行公事,支付系统才算真正有了灾备能力。如果你想了解在持牌网关之上怎么设计商户侧的备援方案,欢迎通过 Telegram 联系@LouisSMARTPAY,或邮件联系[email protected]。