Monzo Stand-In
摘要
Monzo 建立了一个名为 Monzo Stand-in 的独立备份银行基础设施,以确保在重大云中断期间的服务连续性,支持卡支付和银行转账等基本功能。
暂无内容
查看缓存全文
缓存时间: 2026/08/29 03:32
# 通过Monzo备援系统容忍全面云服务中断
来源:https://monzo.com/blog/tolerating-full-cloud-outages-with-monzo-stand-in
我们的客户合理地期望能够全天候365天使用银行卡消费、进行银行转账和支付账单。他们的生活不会因系统维护而停顿,我们也不应该如此。我们投入大量工程精力来最小化技术迁移(https://monzo.com/blog/how-we-run-migrations-across-2800-microservices)及其他日常运营中的中断风险,但导致意外停机的不可预见事件无法完全消除。
Monzo高度重视可靠性,因此我们构建了完全独立的备份银行基础设施——Monzo备援系统,为客户提供另一层防护,确保他们能继续使用我们提供的核心服务。我们将Monzo备援系统视为最终备份机制,而非向客户提供可靠服务的主要途径,它为我们提供了额外的防线。
## **Monzo备援系统架构**
Monzo备援系统是一套独立的系统组,运行在Google Cloud Platform (GCP)上,能够在主平台(运行在Amazon Web Services, AWS)发生重大事故时接管服务。它支持Monzo最重要的功能,包括银行卡消费、现金存取、银行转账收发、账户余额与交易查询,以及卡片冻结/解冻等。
我们的主平台与备援平台相互独立运行,各自由Kubernetes集群承载,在数据库、队列系统和锁机制等典型平台组件之上运行独特的服务集。两个平台的服务具有唯一性——备援平台的服务绝不会在主平台运行,反之亦然,即使处理银行卡支付这类通用功能也是如此。
一张展示Monzo主平台(左侧,含3000个微服务)与备援平台(右侧,含18个微服务)关系的示意图,显示支付指令和Monzo应用流量可路由至两个平台。
每个平台都能独立做出交易批准/拒绝决策,并可通过多个物理数据中心建立与支付网络的连接。
Monzo备援系统还运行了一套有限的API端点,在启用备援时提供精简功能。Monzo应用会在后台定期检测备援系统是否启用,若已启用则切换至简化的界面,仅支持核心功能。
四张Monzo应用界面截图:从左至右依次为常规应用概览页、显示系统故障及可用功能列表的提示页、启用备援时的简化账户视图、以及当前账户详情与交易的简化视图。
## **差异化系统设计助力风险缓解**
看似反常的是,我们为Monzo备援系统从零构建全新服务,而非部署主平台的相同服务。这种选择背后有多重考量。
若运行完全相同的服务集,我们需要在双平台间复制所有数据。为实现这一目标,必须保持数据的强一致性——这意味着只有数据同时写入两个平台,数据库写入操作才会被视为成功。任一平台不可用时,我们将无法在不牺牲一致性的前提下执行任何写入操作,反而会降低整体可用性。
与其维持强一致性,我们接受数据复制是阻塞性且最终一致的,但诸如账本系统(https://monzo.com/blog/2022/02/18/how-we-calculate-balances)则无法容忍最终一致的数据。
### **差异化软件降低同类故障概率**
主平台跨AWS可用区运行,并为所有服务部署多个副本。我们设计系统时具备扩展性,并在非关键依赖出错时优雅降级。尽管主平台架构已内置弹性机制,但如此复杂的系统仍可能以意想不到的方式故障。
主平台故障的潜在原因多种多样。虽然我们常认为需要规避的是云服务商停机,但代码或流程中的缺陷同样可能导致系统中断。
传统灾难恢复系统主要考虑硬件故障,认为平台面临的最大风险是网络中断或磁盘损坏。AWS、GCP、Azure等云平台提供商已基本解决了硬件故障导致的停机,但灾难恢复机制并未真正演进。如今,即使拥有多个数据中心,若所有数据中心运行相同软件,效果依然有限。
备援环境与主平台的独立性越高,同类问题影响备援平台的风险就越小。就我们而言,两个平台各自运行独立的发卡处理代码,均具备交易授权能力。虽然双平台行为预期相似,但我们分别实现并尽量减少对共享代码的依赖。
### **轻量化系统成本可控**
我们持续密切监控平台运行成本。Monzo备援系统在后台运行的成本仅为主平台的1%,即使在重大事故中启用,预期成本增幅也极其有限。若要运行所有相同系统并复制全部数据,所需计算资源和维护人力成本将大幅增加,甚至可能使平台总成本翻倍。
## **双平台间数据同步**
Monzo备援系统仅包含支持少量功能所需的最小状态数据,包括余额和有限的历史交易记录、处理支付所需的卡片及账户详细信息,以及资金池、收款人等其他辅助数据。当主平台中任一数据发生变更时,备援数据同步器会将更新写入备援平台。主平台产生的所有处理结果、状态变更及其他影响事件会发布到事件系统(https://monzo.com/blog/2021/10/14/an-introduction-to-monzos-data-stack),备援数据同步器会消费其中部分事件以触发备援平台的状态更新流程。
数据流向示意图:显示备援数据同步器从主平台的多个上游服务(如交易创建事件)消费事件,并将数据发送至备援平台的数据存储。图中还展示了加密令牌化数据在主平台与备援平台间的交换。
所有从主平台同步至备援平台的数据均视为不可变数据。我们不要求备援平台始终基于完全一致的世界观运行,但由于同步的实时特性,实际视图极度接近完美一致性。我们严密监控这一最终一致同步过程的延迟,并在延迟超过容忍阈值时发出告警。
令牌化数据(如加密的卡号PAN (https://en.wikipedia.org/wiki/Payment_card_number))的同步流程类似但略有不同:我们在双平台的令牌化系统间交换使用不同密钥集(图中标记为A和B)加密的数据。
### **从备援平台同步状态**
启用Monzo备援系统时,它会产生与主平台类似的处理决策和状态变更。但由于这不是主平台,这些结果仅在我们使用备援期间具有权威性。
备援平台中的新状态与从主平台同步的不可变数据分开存储,所有影响事件记录在持久化队列中,供主平台在恢复后消费。若主平台仅部分不可用,它可能立即消费该队列;若遭遇全面停机,则可能延迟至未来某个时间点处理。
此日志中的影响记录被称为Monzo建议指令(Advices),它们向主平台报告已创建的影响(例如批准的卡支付),我们期望主平台如实应用这些建议指令的效果。
示意图展示备援平台中的服务将其状态存储至数据存储,并通过GCP PubSub发布Monzo建议指令至持久化队列。主平台的消费服务在可用时会消费该PubSub主题,最终通过service.mastercard等下游服务(如账本资金划转)应用这些建议指令。
主平台是我们记录真实数据的权威系统,在Monzo备援系统启用期间绝不充当记录系统的角色。这意味着基于备援平台上可能不一致的客户余额视图应用Monzo建议指令时,我们可能批准了主平台认为余额不足的交易,导致客户出现未经授权的透支。我们在主平台设置了多项控制措施应对此类情况,但实际发生概率极低。
### **双平台数据关联处理**
将备援平台的Monzo建议指令应用于主平台时,我们预期下游系统会创建等效状态。例如备援平台的卡支付建议指令将触发主平台账本的资金划转。
这引发了一个小问题:双平台现存在表示同一支付的状态,而主平台账本资金划转时,数据同步器会如前所述将交易同步至备援平台。
示意图展示备援平台服务写入数据存储的StandinTransaction,在主平台应用Monzo建议指令后,会作为SyncedTransaction最终同步回备援平台。
为避免备援平台中交易及其他影响的重复计算,我们为`StandinTransactions`和`SyncedTransactions`生成关联ID(图中标记为A),并在备援平台使用数据时对关联交易进行视图合并。
## **启用Monzo备援系统**
前文提到了启用备援系统的能力,此处将详细说明。我们在主平台和备援平台分别运行备援配置服务,两者大部分API兼容,共同协调确定启用哪个平台、启用备援平台的哪些组件,以及为哪些用户启用。当检测到对客户至关重要的服务中断时,我们可通过配置系统启用对应的Monzo备援组件。
目前我们通过备援平台CLI工具更新配置,但进一步开发后可实现全自动化——通过触发配置系统自动执行工程师手动操作时使用的相同判断逻辑。
终端模拟器截图显示备援事故工具界面:展示Monzo备援系统当前状态(未对任何用户启用),以及工程师可用的操作选项(包括route-payments、redirect-apps和prescale)。
即使主平台完全不可用,该系统仍可运作。如前所述,Monzo应用会在后台定期检测双平台状态,以决定是否显示备援系统的精简界面。停用Monzo备援系统同样是工程师的主动决策,因此当主平台API恢复时,应用流量不会立即全部回切。我们能够逐步将Monzo应用流量迁移回主平台。
### **通过主平台路由支付流量**
启用支付处理功能时,系统最初仍通过主平台路由支付流量,再由其代理转发至备援平台。虽然看似违反直觉,但这赋予我们更强的控制力——可精细调控有多少客户迁至备援系统、或从备援系统迁回,甚至可针对特定客户群体进行迁移,而其他客户的支付仍保持在主平台处理。该机制也帮助我们实现故障快速恢复。
支付流量路由决策系统基于每条收到的支付消息运行,判断应路由至主平台还是备援平台的支付处理器。
数据流示意图:显示从Mastercard经Monzo数据中心流入主平台的过程。主平台决定是否在备援系统中处理Mastercard消息,若确定处理,则将消息发送至备援平台的service.standin.mastercard服务。
此机制适用于多数事故场景,但若主平台完全瘫痪,支付处理将难以正常进行。此时我们可通过数据中心将备援平台直接连接至支付网络。这是更为激进的方案,因为我们对哪些客户或多少流量导向备援平台的控制力大幅减弱,但缺乏该选项将严重影响系统韧性。
无论是通过主平台代理支付至备援平台,还是由备援平台直接接收支付,这两种路由方式都在生产环境中经过持续严格的测试验证,确保系统在需要时能正常运作。
## **您可能已体验过Monzo备援系统**
2024年8月,我们遭遇了影响大多数系统(包括支付处理和Monzo应用服务)的重大平台事故。停机持续约1小时,但我们在检测到问题后迅速启用Monzo备援系统,确保客户仍能正常使用资金。
这并非Monzo备援系统首次启用——事实上,为持续测试,我们始终有少量客户使用该系统。但此次是首次为全部客户启用所有备援组件。如果您在此期间打开Monzo应用,会看到与日常体验明显不同的界面,但查余额、银行转账、用卡等核心功能保持正常运行。
## **结语**
Monzo备援系统取得了巨大成功,帮助我们从政策到实践证明了系统具备抵御关键平台中断的能力。随着技术领导者和监管机构日益重视运营韧性,欧盟《数字运营韧性法案》(DORA,https://www.eiopa.europa.eu/digital-operational-resilience-act-dora_en)等法规陆续生效,我们相信Monzo正以前瞻性实践引领变革。
相似文章
PaymentKit
PaymentKit是一款旨在抵御处理器停机的计费解决方案,确保服务连续性。
Monid
Monid 是一款统一加密钱包,专为让 AI 代理支付其所需的任何工具或服务而设计。
用于弹性支付系统的单元化架构
美国运通描述了其核心支付生态系统采用的单元化架构,该架构能够隔离故障、降低延迟并扩展容量。这种方法将微服务和数据库分组到独立的单元中,以限制爆炸半径。
SyncStaq
SyncStaq 通过自动同步,让 Google Sheets 中的 Stripe 账单数据始终保持最新。
Task Monki
Task Monki 是一款工具,允许用户通过完整的开发流程运行编码代理。