01 背景

1.1 初识混沌工程

首先我们先了解一下什么是混沌工程?简单而言,混沌工程是在系统上进行实验的技术手段,目的是建立对系统抵御生产环境中失控条件的能力以及信心。这主要体现在两个方面,从系统角度来讲,混沌工程可以提升我们架构的容错能力和韧性,降低故障发生率和复发率,提升系统用户在使用时的体验;从人员角度来讲,通过混沌工程我们可以加深对架构的理解,在处理故障时能提高整体的应急效率,并且能主动去探究系统中潜在的一些问题。

混沌工程最早可以追溯到2008年,当时奈飞公司(Netflix)因数据库故障造成了一次巨大的损失,于是他们便围绕着稳定性体系做出了一些探索和建设。直到2015年,混沌工程的理念才被奈飞正式的提出。2019年,阿里云推出了开源工具Chaos Blade;2020年,PingCAP开源了Chaos Mesh,这也标志着国内在混沌工程领域也有了成熟的产品。

来源:中国信息通信研究院,2021年

1.2 现状

下面是当前美团数据库运维的一些现状,这里从五个维度展开:首先集群规模(包括集群的大小和数量)的线性增长;第二,集群访问量的持续增加,当然这也是美团业务增长的必然结果;第三,线上遇到的故障种类也越来越多;第四,单位时间故障的影响也越来越大;第五,一些小概率事件的发生也随着集群规模的扩大成为了可能。

1.3 痛点&作用

基于以上的问题,我们整体上对于数据库集群的稳定性要求也越来越高。所以,围绕着稳定性建设,数据库团队在故障的预防、发现、分析、恢复以及事后复盘5个方面做了很多工作。其中在故障预防方面,我们会通过故障演练探索不同故障场景对我们业务的影响,提升故障发生时业务系统整体的容错能力。早期的时候,我们通过人工的方式来做故障演练,但人工演练在以下四个方面存在很大的问题:

  1. 在演练场景方面,人工演练能演练的场景比较少,演练场景的复杂度也比较高;
  2. 在演练覆盖率方面,人工演练无法覆盖大多数的集群,也就无法保证常态化的故障演练;
  3. 在演练规模方面,人工演练没有办法进行大规模演练,在遇到一些机房或者交换机级的故障时,切换能力无法得到有效验证;
  4. 在影响范围方面,人工演练在整个演练过程中不能很好地控制爆炸半径,遇到问题不能快速止损。

基于人工演练的这些痛点问题,我们设计并建设了数据库故障演练平台,这个平台的作用主要体现在以下四个方面:第一,验证故障发生时组件的防守能力;第二,通过数据库大规模容灾演练,验证数据库集群的容灾能力;第三,可以验证故障发生时相关预案(业务、DBA)的有效性;第四,可以预知故障对业务造成的各种影响。

02 建设实践

2.1 体系架构

当前,数据库故障演练平台体系架构主要包括如下六个模块:

  1. 权限管理,控制演练发起人,可以对哪些集群发起故障演练;
  2. 演练评估,演练之前为了避免演练风险,会对集群做一些检查,比如集群的高可用是否开启,拓扑是否符合要求,演练时间是否处在集群访问的高峰期等;
  3. 故障注入,在相关的检查通过后,真正去执行故障的下发;
  4. 指标观测,在整个演练期间会通过采集一些可以反映稳态的数据,比如以业务的访问成功率、业务的响应延迟等等,来分析故障演练对业务造成的影响;
  5. 终止注入,在演练过程中发现整体影响比较大,或者有一些非可控的影响,可以立刻终止故障演练,避免故障演练对线上业务造成的影响进一步扩大;
  6. 智能分析,在演练结束之后,可以通过采集一些反应故障注入或者是防守组件的相关数据判定本次故障演练是否符合预期。

当前故障注入支持的主机类型比较全面,可以在物理机、虚拟机、容器上做故障演练。

2.2 能力全景

这部分主要介绍一下我们故障演练平台的能力全景,它主要规划了我们当前数据库故障演练平台的一些核心能力,整体的细节如下图所示:

  • 从支持的数据库来看,当前我们主要支持MySQL的故障演练;
  • 支持的数据库组件有数据库访问中间件、数据传输、高可用系统和Binlog Server,我们会在后续的迭代中逐步支持,当前我们正在接入数据库访问中间件的一些演练场景;
  • 在整个故障演练过程中,我们会依赖高可用、容灾管控、故障诊断、故障兜底以及拓扑自愈等多个方面的能力,主要是验证上面提到的这些组件在整个演练过程中的表现是否符合预期;
  • 当前,平台自身已经形成了从故障编排、故障注入、指标观测、故障终止、分析复盘的一个闭环。

2.3 故障注入能力

关于故障注入能力,当前支持的故障场景主要包括5个(如下图所示),目前我们主要建设的是宕机类(包括主库宕机、从库宕机)、主从延迟以及从库活跃连接多,由于当前线上80%的故障都是由这几个场景引起的,这也是我们目前没有建设过多故障场景的主要原因。后面我们还会规划建设高可用的链路故障,比如数据库和高可用同时出问题时,高可用的表现是怎么样的,是否能够顺利的进行切换。

在故障编排方面,我们通过建立一个任务内的子任务间的串行故障和并行故障的编排机制,来实现演练任务的统一编排。

在并发能力上,当前故障演练平台保守的并发故障注入能力是在一分钟实现5000+节点的故障注入,目前这个能力已经可以满足我们对于大规模故障演练的整体需求。

2.4 演练流程

整个演练流程主要分成三部分,演练前、演练中和演练后,同时我们也形成了风险评估、风险复核、一键终止、故障复盘的能力闭环。

在演练前,我们主要做三个方面的工作:

  • 针对演练集群做风险评估,比如演练集群的高可用是否开启、拓扑是否符合要求;
  • 利用多级审批机制,让业务和相关的DBA知晓整个演练的风险;
  • 在演练前创建相关交流群,把故障演练相关的信息在群里进行周知。

在演练中,有两方面的工作:

  • 在故障注入前,做一下前置检查,主要目的是在建立演练任务后和故障注入前这个时间段,防止因集群拓扑变化产生风险,比如演练的场景是从库宕机,这种情况下如果发生切换,故障注入的节点很有可能变成了主库;
  • 如果一个任务里含有多个子任务,而某一个子任务发生了故障注入失败,那么后续演练我们会自动终止。

在演练结束后,我们会进行故障清理,完成后做演练的数据收集,用于复盘,并据此完善相关的风险管控流程。

2.5 爆炸半径控制

提到混沌工程,就不得不提到爆炸半径控制的问题,当前我们主要从两个维度、三个方面做了一些控制。

第一个维度是物理隔离,它包含两方面:

  • 场景维度隔离,即在同一时间点、单个数据库的集群只能注入单一类型的故障,主要是为了避免在单个演练任务中如果针对一个数据库集群注入多种故障,整体影响不容易被评估。
  • 机器维度隔离,单个集群故障注入只能选定一个特定机器,而不能选择多个机器。

第二个维度是流量控制,主要是通过中间件按权重下发少部分流量到演练节点实现,流量控制能从一个更精细的维度来控制演练的风险。

另外,我们在演练前、演练中和演练后都有相关的检查或措施,能够保证在演练期间出现问题后迅速把影响降到最低,这也是另外一种变相的爆炸半径控制。本质上来说,爆炸半径和通过演练发现的问题数量会有一个正比的关系,即爆炸半径控制得越小,整个故障演练对业务的影响也就越小。但与此同时,整个故障演练暴露出来的问题,就会比较有限,所以在建设过程中要做一个取舍。如果想发现更多的问题,那爆炸半径就要设计的大一些。当前,综合考量多种因素,我们还是把爆炸半径控制在一个相对合理范围去进行故障演练,让业务以一个更低的成本进行故障演练。

2.6 演练复盘

当演练结束后,我们需要对整体的演练结果做客观的评价分析,进而判断这次演练整体是否达到预期。演练复盘内容包括演练整体流程、存在的问题以及针对问题形成的相关改进点,它可以用来指导后续的演练。如果本次演练不符合预期,我们会通过演练复盘功能打通故障演练平台和故障复盘两大产品,自动生成演练相关的时间线,从而更好地进行人工复盘。

演练复盘主要是分为四部分:

  • 第一部分是演练复盘的概览信息,它主要是包含六个方面:① 演练时长;② 本次演练涉及的集群数;③ 演练场景数;④ 演练成功率,即故障注入的成功率;⑤ 演练过程中产生的告警数;⑥ 演练期间业务请求的成功率。
  • 第二部分是关键步骤,这里收集了在整个演练过程中非常关键、非常核心的步骤,以及它整体的指标数据,这些可以帮助我们分析平台本身亦或是防守组件的相关表现是否符合预期。
  • 第三部分是在演练过程中涉及的核心防守组件的指标数据,比如针对主库宕机,我们主要关心两方面数据:一是故障注入后,高可用组件用了多长时间才发现这个故障,二是在发现了这个故障后切换花了多长时间。通过这些数据,就可以知道在本次演练过程中防守组件的表现是否符合预期。
  • 第四部分是演练详情,它是针对单个集群的演练过程绘制的完整的时间线信息,可以通过这些信息看到一个演练集群从前置检查到故障注入,到告警产生,到防守组件的介入,再到故障清理呈现出的一个非常详细的时间线数据,如下图所示:

2.7 随机、无通知演练

从2022年开始,我们开始建设随机、无通知演练能力。之前故障演练平台主要是在特定时间、特定场景下的演练,并且在整个演练过程会组织相关的人员协同跟进整个演练过程。但是,故障的发生是一个非常随机的行为,它不会给人足够的时间去准备、应对。而随机无通知演练功能,就是希望建设这样的能力,可以在非特定时间、非特定集群、非特定场景进行故障演练,在一定程度上填补了故障演练的空白,也是故障演练平台向混沌工程演进的一个里程碑。整个演练过程主要分成三个部分:

第一部分是需要添加演练计划,其主要内容包括三个方面:

  • 可以通过集群、场景、演练时间这3个维度,去控制哪些集群可以演练哪些场景,在什么时间可以进行随机无通知演练;
  • 按集群、场景维度组合去做相关风险检查,以此来保证添加的这些集群可以进行相关场景的演练;
  • 和常规故障演练相似的是,它也提供了多维审批,可以让相关业务人员或者DBA知晓个整个演练的风险。

第二部分是演练任务生成,有了演练计划后,我们按演练计划随机搭配生成演练任务并进行周知,和常规演练最大不同是我们不会周知演练的具体时间(会周知演练集群、场景),主要是为了模拟故障发生的随机性。随着后面整体能力的升级迭代,我们会逐步去掉在集群、场景维度的周知。

第三部分是演练任务执行,它完全复用我们常规故障演练的功能,也可以在演练前取消、演练中终止,演练后可以自动恢复整个集群的拓扑。

2.8 演练模式对比

下面我们将常规故障演练、随机无通知演练以及混沌工程作一下对比,如下表所示:

  • 首先从演练目的维度来看:常规故障演练目的性非常强,它主要是验证已知的问题场景是否会再次造成生产上的事故;随机演练主要是在已知的故障场景、在有限的集群范围内,是否会产生问题;混沌工程的演练目的性最弱,它主要是检验未知的故障场景是否会造成问题。
  • 从是否有人值守的维度来看:常规故障演练需要有人值守;随机无通知演练是朝着无人值守方向发展的,但当前鉴于我们的能力还在建设初期,所以也会增加一些相关的值守机制来控制演练风险;混沌工程是完全无人值守的,因为也无法去值守一个混沌工程的“混沌”实验。
  • 从事先周知的维度来看:常规故障演练需要明确进行周知;随机无通知演练当前在有限集群和有限场景范围内进行演练(会周知演练集群、演练场景),不会周知具体的演练时间;混沌工程是完全无周知的演练形式。

2.9 演练运营体系

下面是数据库故障演练平台的运营体系的建设,主要关注四个部分:

首先是演练核心指标:

  • 一是在一段时间内,共进行了多少次演练,涉及演练集群数有多少个;
  • 二是在一段时间内演练集群和演练场景的覆盖率以及达标率;
  • 三是故障演练结束后的反馈,即演练是否符合预期。

第二部分是大规模演练的核心指标,我们主要关注三个方面:

  • 第一方面是每次大规模演练的演练规模;
  • 第二方面是故障注入的成功率;
  • 第三方面是故障注入的耗时分布,主要统计在某一个时间点,完成了多少实例的故障注入。

第三部分是业务接入指标,一方面统计核心业务的接入情况,同时也会反映一下DBA在不同业务线的推广情况。

第四部分是平台能力指标,一方面是平台接口成功率,另一方面是平台接口的相关耗时。

03 落地情况

3.1 演练推广

本部分会介绍故障演练平台在美团内部的落地情况。首先在推广层面,我们主要采用三种形式:

  • 第一种形式是故障驱动方式,如果线上发生了特定的故障场景,导致业务损失,我们就会进行相关故障场景的容忍能力建设以及验证。
  • 第二种形式是主动演练,通过定期学习一些故障案例,判断相关的故障案例中的相关故障场景是否会对目前负责的业务产生影响,也可以通过故障演练平台做简单的摸底。
  • 第三种形式是DBA主动策划组织,比如2022年,我们进行了三次规模比较大的演练,主要验证在特定故障场景下,业务的容错能力、高可用的防守能力是否符合预期。

3.2 实验环境

在混沌实验的环境选择上,我们目前提供了三种不同的环境:

  • 第一种是线下环境,主要是用来发现问题后进行相关预案的建设和验证;
  • 第二种是线上演练环境,主要是通过大规模的容灾演练,去验证防守组件的防守能力是否符合预期;
  • 第三种是线上真实环境,就是我们真正的线上业务集群,主要通过具体业务进行相关故障场景的演练,能够更加真实、全面地验证故障的影响,以及相关预案的有效性。

3.3 演练规模

接下来是演练规模,演练的规模越大,影响的范围越大。我们的演练规模可以划分成三类:

  • 第一类是单集群演练,主要验证故障影响及预案有效性;
  • 第二类是中小规模演练,主要通过规模化的演练,去验证特定故障场景对业务的影响;
  • 第三类是大规模的集群演练,主要验证容灾能力,以及相关防守组件的防守能力是否符合预期。

3.4 场景 & 等级

在整体推进方面,我们目前会从两个维度进行演练:

  • 第一个维度,我们会根据故障影响的严重程度,做无损到有损场景的演练;
  • 第二个维度,演练会从低等级集群开始,最终过渡到高等级集群,这样做的目的是先给业务建立一个对于故障演练的信心,之后逐步在高等级集群中发挥故障演练的重要作用。

3.5 演练运营数据

下面是常规故障演练、随机无通知演练以及大规模故障演练的一些相关数据:

  • 从常规故障演练的数据可以看出,当前我们整体上的常规故障演练覆盖率是偏低的。
  • 随机功能演练是2022年第四季度才建设完成的能力,到目前还是初级推广阶段,所以整体上演练次数比较少,2023年的主要目标是通过在核心业务线的推广,不断提高演练集群的覆盖率,以期发现更多的问题。
  • 大规模演练从2022年下半年开始,在演练频次有非常大的提高,这主要是为了更好地验证数据库底层依赖的防守能力在面临大规模故障时的表现。如果发现相关组件存在问题,我们也可以更好地辅助这些组件去做迭代,辅助建设相关的能力。上图统计的是单任务演练规模超过100个集群的数据,但如果按照20或50个集群进行统计汇总,那么大规模演练的任务次数还会更多。

3.6 防守体系能力验证

在防守体系能力建设层面,我们主要验证防守组件的三个核心能力:

  • 第一个从高用来看,主要验证RTO和RPO是否符合预期,以及在大规模故障场景下,其切换能力是否达标。
  • 第二个从弹性伸缩来看,主要验证在单集群或规模化演练前提下,整体弹性扩容决策能力是否达到期望,以及在小规模场景下实地验证弹性扩容的并发能力。
  • 第三个从观测来看,主要验证当大规模演练发生时,观测工具的及时性以及准确性。

3.7 业务演练收益

诚然,演练会对业务方造成一些“打扰”,但是业务方也会积极配合我们做这项工作,因为故障演练对业务方也有一些收益:一方面,业务方可以通过演练发现一些隐藏的问题,从而规避更大的风险;另一方面,我们在发现业务问题的同时,也能验证相关防守组件的表现是否符合预期。更多的细节,大家可以参考下图:

04 未来展望

4.1 混沌工程成熟度模型

下图是混沌工程成熟度模型(CEEM),右边是我们当前的数据库故障演练平台和标准的对比。可以明显地看到,当前我们在一些维度上做的还不够,比如当前故障场景的覆盖程度、稳态指标的覆盖程度、实验观测、文化建设等方面都存在一定的不足,而这些不足其实也是我们后续着重要改进的点。

4.2 混沌工程成熟度等级

关于混沌工程成熟等级,我们也做了一些总结:

  • 从开展程度来看,当前我们只是在一些核心部门进行了故障演练,在稳定提升方面会有一些相关建设的成果;
  • 从落地收获来看,一是可以验证故障的影响,二是可以提高业务系统对于故障的容忍度,三是可以通过数据库故障演练平台,评估我们在稳定性建设方面的一些成果;
  • 从整体评级来看,我们当前还处于基础阶段,后面也会继续在公司更多的核心部门推广数据库故障演练平台,持续为业务系统稳定性提升做出更大的贡献。

4.3 具体规划

在最后部分,我们分享一下关于未来的规划。在具体路径层面,我们会从五个方面进行开展工作:

  • 第一,要降低单次演练成本,比如降低单次演练的介入率,无论是业务还是DBA。
  • 第二,丰富故障演练场景,建设链路故障注入能力,从服务端故障向端到端故障做一个扩展。
  • 第三,增强可观测性,当前整个故障演练平台在观测指标方面相对比较缺乏,后续我们希望通过引入更多的观测指标,从而更好地观测整个混沌工程的实验过程。
  • 第四,智能化,主要聚焦三方面:① 建设整个稳态系统,因为当前我们整个故障演练是否符合预期,主要还是通过人工或者DBA来进行判断,有了稳态系统后,可以通过稳态系统去判断;② 根据稳态系统相关指标建设故障自动终止能力;③ 建设相关的演练推荐能力,因为现在业务线推广演练时,可能还不清楚我们该在哪些集群演练哪些场景,当有了这个能力后,业务在演练时会有更强的针对性。
  • 第五,希望能够实现演练常态化,即通过常态化演练去发现业务端更多的隐患。