本文从业务角度介绍微信支付实践混沌工程落地的思考,通过多分区的架构来控制最小爆炸半径,在高价值的基础组件和微信支付核心业务场景上探索,并基于高可用原则、历史故障分析推导故障原子的开发,是一篇全面的混沌工程建设实践。
作者 | 刘斌 责编 | 夏萌
出品 | 腾讯云开发者
业务场景:微信支付服务于千万商户和亿级用户,可用性要求高于 5 个 9;
落地矛盾:注入故障需贴近实际故障环境,对现网业务无影响/弱影响;
实践难点:如何控制最小半径,如何高效、全面挖掘风险;
业务收益:发现多处组件和业务风险,从0到1建设起混沌工程系统;
未来展望:更丰富的故障原子;自动化;支持多类半径实验。
为什么要做混沌工程
1.1 目标起点
微信支付是国家关键信息基础设施,服务千万商户和亿级用户,可用性要求高于5个9。
1.2 分析:影响可用性的主要因素及应对
为了分析影响可用性的因素,我们对2018 ~ 2021近几年微信支付的故障复盘数据分类,发现软硬件异常导致的故障占比较高(如下图的基础设施、组件、上下游部分)。
各类引发故障的因素,微信支付采取了相应的应对措施,如
功能/程序缺陷:单元测试,集成测试,UAT 测试,流量回放;
容量不足:常态化压测,自动弹性伸缩;
人为破坏(人因):去登陆 IDC,变更审核,权限控制,模块认证;
但对于软硬件故障,虽然基础组件会涉及一些容错处理,但设计是否全面、开发是否完全实现、真实场景是否有效,没有统一的工具和验收标准,并推动解决。
如何检验系统具备应对软硬件异常的容灾能力,我们调研了公司和业界的方法,其中演习和混沌工程最为常见和有效。它们都强调在线上实施,目的都是提高系统的可靠性和弹性,但方法和侧重点有所不同(区别两者概念和思路,对实际落地影响较大)。
1.2.1 演习
演习通常是有明确的执行计划和预期,要求注入故障的影响已知且明确。
更关注人的反应和应急响应计划,还包括非系统因素都在考量范围。比如验证某个系统失效后的,人为干预流程、机制是否顺畅等。
1.2.2 混沌工程
(公司和业界有非常多的关于混沌工程的概念介绍,如不了解可先自行搜索,不再赘述。)
混沌工程在目标上更强调 发现未知的风险 ,更关注系统的弹性,不涉及系统外的因素。其中 Netflix 提出的混沌工程五大原则是业界落地实践的普遍共识:
建立稳定状态的假设;
用多样的现实世界事件做验证;
在生产环境中进行实验;
自动化实验以持续运行;
控制最小化爆炸半径。
其中多样化的事件和控制爆炸半径的方法,相对演习有明显差异。也正是控制了爆炸半径,混沌工程里注入故障的强度、复杂度远高于演习能力,能更全面、真实的模拟现网故障,以达到」发现未知风险「的目的。
此前,演习是微信支付容灾验证的重要手段,我们发现演习因为没有系统的爆炸半径控制方法,所以从工具开发、监控稳态识别、事件的多样性、自动化等方面,演习都需要较多的定制开发和人工实时观察,人力投入成本较高。
因此,引入混沌工程体系,通过有效的控制爆炸半径,进而更大幅度的注入异常并适当建设自动化能力,来识别系统薄弱点并推动持续治理来提高可用性,是当前值得探索的方向。
1.3 可行性
落地混沌工程有两大矛盾点:
故障有效,注入的故障贴近实际发生故障环境;
业务安全,注入故障对现网业务无影响或者影响较低。
为了贴近真实环境,注入故障离真实环境越近越有效,但这又势必影响业务可用性。且微信支付对可用性要求高,不接受不可预知的风险。如果没有解决业务安全问题,就引入混沌工程「探索未知风险」的期望就较难落地。
在2021年,微信商业支付做了多分区改造,将业务流量路由到不同分区,分区间相互独立、互不影响,分区间环境一致性通过 DevOps 部署保证。在分区隔离的 IDC 环境里注入故障,调配可控的流量,既能贴近生产环境,又能确保故障收敛、控制爆炸半径。这样,微信商户支付落地混沌工程已具备条件和可行性。
如何落地
从业界落地混沌工程经验来看,基本是围绕 Netflix 提出的5大原则展开。
建立稳定状态的假设,即从用户角度衡量业务健康度,一般业务都有现成的业务监控,大多情况无需额外开发。
用多样的现实世界事件做验证 即 丰富注入故障的类型,自动化实验以持续运行 即 降低人工参与成本,两者都需要额外开发,但先开发哪些、做到什么程度,可结合业务目标,更多的是开发人力成本和可挖掘到的风险收益之间 ROI 考量。
在生产环境中进行实验和控制最小化爆炸半径,是混沌工程的有效性和安全性的两个关键问题。
因此,落地混沌工程的主要难点是:
安全、有效的实验;
高效、全面的发掘风险。
2.1 安全、有效的实验
不同的技术选型对应的有效性和安全性如下:
一般来说,有效性和安全性很难同时满足,而且是此消彼长的关系,越是希望真实还原故障,就需要在有业务流量的真实环境中模拟故障,这又会影响业务安全;但若一味追求安全,不能对业务有任务影响,就无法还原故障发生的真实场景,又很难发现问题。可结合实验目标,确定业务能接受最低限度的安全性,来选择有效性最高的方案。
2.1.1 安全:不影响线上业务
控制爆炸半径
爆炸半径的方案选择,在混沌工程实施的不同阶段,也是可以调整的。对系统可用性的信心越足,越是可以贴近真实环境,因此前期可以在有效性低的环境中实验,当实验手段很难发现新问题且发现的问题都已解决时,可以考虑升级到有效性更高的方案。
对微信商业支付,如前文介绍在2021年已经进行了多分区改造,因此我们在多分区架构上,单独规划了分混沌分区路由和4个业务分区,部署的业务逻辑模块、存储、组件等都与生产分区完全一致,前期放入仿真流量到混沌分区后注入故障,当对系统具备足够的信心后,后期在生产分区注入故障。
由于多分区仅对核心业务做了改造,仍存在外部依赖服务,为了防止混沌实验对外部依赖的影响,对不同场景的风险源做了相应处理:
特殊限制与审批
考虑」数据篡改「类的故障,可能会导致写脏数据,尤其是篡改业务执行主体(如商户 ID、用户 ID)写脏真实业务数据的风险,因此禁止」篡改执行主体「的故障。
考虑执行的实验的风险,我们对这些场景加了审批:
「修改」类的故障加审批。避免写脏异常影响真实环境,由leader二次评估确认。
非资源负责人执行审批。如对他人模块实验(模块混部对母机实验校常见),避免无法发现其它业务异常。
非工作时间实验审批。避免实验异常,干预时间长。
2.1.2 有效:贴近真实环境
我们主要在隔离的混沌分区实验,实验环境与真实环境一致性越高,真实环境出现类似的问题概率就越大。
静态:部署环境的一致性
部署环境一致性的主要维度如下:
我们将上述高一致性要求的地域、园区、容器、二进制、配置,做到 DevOps 部署工具中,上线模块、发布变更时做到与投产环境一致。
动态:实验流量的逼真度
实验流量与线上接近的目的,一是还原机器/容器负载情况,二是还原业务执行的分支,两者在某些复杂组合场景下,是否会触发未知风险。我们从两个维度来评价流量仿真程度:
基于这两个指标,有两个不同方向:
考虑前期建设成本和不确定性,我们选择了人造流量方案。
2.2 高效、全面的发掘风险
从0到1建设混沌工程系统和业务落地,我们遇到了这两类问题:
我们选择从业务目标出发,优先看高价值的风险点,工具配合业务目标逐步丰富故障原子。根据不同阶段的侧重点,将项目的实施路径拆分两个阶段:
2.2.1 发掘高价值风险
前期,人力、工具有限的条件下,如何发掘高价值风险(高 ROI)?
较简单的方法是:随机注入。工具团队可根据近几年的故障类型,按照优先级开发出对应的故障原子,无差别的注入到目标模块。当前期自动注入、稳态分析不够健全的情况下,仍需人工参与,这种方法有2个局限:
实施的业务团队人力投入大:人工注入故障,人工观察、分析业务监控,以及监控偏离时是否影响业务、是否会扩散风险、是否有其他潜在风险;
工具团队不能做到有的放矢,不能将有效的人力投入到最有价值的原子开发上来。
为了快速找到高价值风险,进而提升大家参与的积极性,我们选了如下2个策略:
1、实验对象从 高价值 往 低价值 覆盖。根据这个思路,得到了优先实施的模块。1)公共组件:RPC 框架、队列、存储 、缓存,安全认证、日志等;2)生命线业务:收付结退。
2、基于高可用原则拆解,得到工具待开发的原子需求和待注入的资源。
通过这些策略,我们快速的找到 HTTP 接入模块、事件中心、跨城组件等微信基础组件的多个高风险的共性问题。
2.2.2 找全风险
后期,如何增强覆盖面,发掘更多未知的黑天鹅风险?
上述方法,只能覆盖到有限的故障域,而实际故障往往是由多个事件同时发生而触发,因此后期加强单原子无差别的注入和组合故障的注入可以发现更多中长尾问题。
对于组合故障,如果也是无差别策略,那么组合空间极大,就以微信支付委托代扣业务为例:
单故障注入:18模块 * 15个故障原子 = 270个,即单原子无差别的注入次数;
2个组合空间为 C2270 = 36315,任一组合空间为2270。
即使工具已经具备自动注入、自动分析的能力,实验周期和消耗资源也将会很高,因此合理的剪枝很有必要,可采用基于相关性由强到弱的多故障组合,如:
模块内构成依赖关联影响(包括三园区容灾设计);
业务内模块间依赖关联影响;
业务间依赖关联影响;
基础设施间依赖关联影响;
潜在依赖关联影响。
2.2.3 自动化
从实验流程来看,除了「修复问题」,另外三个流程可以做到一定程度的自动化。
自动设计
一个实验任务由4个部分组成:
业务资产:集群、模块、接口;集群是多个模块的总称,如某个存储集群包括接入模块、存储模块、元数据模块;
系统资源:业务资产执行所依赖的机器、容器、网络、CPU、磁盘、进程、文件、内存、共享内存等;
故障类型:针对每种系统资源的有多种故障,如机器包括机器重启、机器时间错误等,如网络包括慢、丢包、乱序等。
故障程度:除个别的像机器重启这类0-1类型故障,其它大多数涉及一定程度的故障,比如网络丢包30%,不同程度下的表现略有不同,一般将故障程度拆解成几档,如丢包有单机内10%、30%、50%、80%、100%,再组合多机情况。
一个实验,首先圈出所包含的业务资产,再整理出其依赖的系统资源(除了磁盘、文件、共享内存这几项,其它一般都包含),再展开系统资源的故障类型,最后确定故障程度,有两种策略:
标记资产类型,如标记为某类存储集群,则套用已设计过的实验模板库生成实验任务;
标记业务所适用的高可用原则,如单机/园区剔除能力、异常防御、分区切换、旁路冗余设计等,裁剪掉全展开的无效程度值,如单机剔除原则只容忍下游单机或单园区机器故障所以不生成多机故障,而做了旁路冗余设计的业务则容许旁路模块的所有机器故障所以生成单机故障的必要性就不大。
因此业务需要做的是:圈定资产范围及依赖的系统资源,并标记资产类型或适用于哪些高可用原则,便可自动生成实验任务。
自动执行
系统建设不是一蹴而就的,从手工执行到自动化我们经历了三个阶段:
手动执行单个故障,主要解决0-1的问题,主要精力放在故障原子建设上;
单次批量执行多个故障,采用 yaml 文件记录编排方式,支持串行、并行调度。应用于业务首次实验和定位问题。
定时执行/事件触发执行,主要用于变更回归和可用性巡检场景,因为定时执行也依赖后续的「自动分析」,所以放在最后。
自动分析
上述自动执行减少了「点击」操作的工作量,实验要」完全「自动化,还要结合自动分析,即自动判断是否偏离稳态。一是当稳态偏离正常范围及时停止,避免造成次生灾害;二是只有做到自动分析,才能低成本的「定时执行」,否则每次自动执行后都依赖人工分析,不可持续。
我们根据实验的时间(实验开始时间到实验结束后一个周期),自动匹配与之相关的稳态告警:
业务:业务用例维度监控是否触发告警。强优先级,触发后停止实验。
模块:上下游调用关系是否出现告警。中优先级,触发后不停止实验,展示在实验报告中。
IP/容器:机器和容器是否出现资源异常告警。中优先级,触发后不停止实验,展示在实验报告中。
业务自定义监控,上述无法自动覆盖的监控,由业务配置后自动收集。
2.2.4 风险处理
发现的风险的除了负责人处理外,方法:
个性问题:周知组件、业务负责人处理
共性问题,通过 SOA 治理、架构模式化、完善研发流程等手段来大规模消除,达成组织价值最大化。
对不同时期出现的问题采用不同的策略:
存量:采用了 SOA 治理平台推动修复(SOA 治理是微信支付风险和异常项治理的平台,提供了统一的异常接入、展示、周知、跟进管理的指标数据,在部门内形成了统一的风险治理共识,以快速治理、收敛风险。混沌工程将发现的风险接入 SOA 治理平台,快速治理大面积的共性风险)。
新增:通过 MR 流水线门禁和变更门禁堵住新增,需处理后才能通过。
成果
我们通过一套流程推进:设计实验(建设原子) - 执行实验 - 分析结果(挖掘问题) - 修复问题,在业务风险挖掘和工具建设上都取得了不错的效果。
3.1 业务成果
2021年上线至今,线上0故障,执行实验计划60+个,实验任务500+次,覆盖业务、框架、组件多类场景,并发掘多处风险。
3.2 工具建设成果
微信支付从0到1建设了混沌工程系统(由业务连续性架构中心和支付运维组建设)。
已支持30+种故障原子,典型原子:
页面支持拖拽式编排、串并行编排,并可配置定时启动实验用于常态化验证风险。
通过关联微信支付的模块调用异常告警、业务监控告警,识别正在实验的模块/IP 潜在异常,在实验报告中展示出来,提高实验后分析效率。
总结与展望
4.1 总结
本文从业务角度,介绍微信支付实践混沌工程落地的思考,通过多分区的架构来控制最小爆炸半径,首先在高价值的基础组件和微信支付核心业务场景上探索,并基于高可用原则、历史故障分析推导故障原子的开发。发现了多处共性风险,并推动修复和治理。
4.2 展望
4.2.1 更丰富的故障原子建设
有效性和安全性始终是一个权衡取舍的因素,如前文介绍,微信支付在独立的混沌分区架构中实施,前期使用仿真流量,因此除篡改数据类的原子外,在控制请求量的情况下,注入故障的爆炸半径很小、对线上影响极低。
但出于业务安全的思考惯性,我们在建设故障原子时基本是按照演习的思路建设:先摸清组件原理,逐个组件/业务定制原子,导致前期交付周期较长。若在控制爆炸半径的基础上,开放更多故障注入的自由度,注入更多、强度更大的故障,可以低成本的发现更多有价值的风险。
4.2.2 自动化与稳态识别
自动化包括:注入故障和异常判定,当前系统支持了注入故障的自动化和简单的稳态识别,识别的正确率和召回率还有空间,因此异常判定大多数仍需人工分析。自动异常判定需要较为高级的 AI 能力,很难基于某些特定规则覆盖所有场景。若能做到全面的自动化,其它业务便可低成本落地混沌工程。另外,也可以注入大批量的组合故障,探索更多未知风险。
4.2.3 支持多类爆炸半径的实验
本文在多分区上部署独立的混沌分区,来控制爆炸半径。而对于非核心支付或者非支付的大多数业务,并没有多分区环境,因此要在其它业务实施混沌工程,仍需结合业务安全和有效性来取舍。