最近一两年,我们可以发现混沌工程这个技术变得十分火热,大家都知道它变成了一个新的风口。常说做事情要顺势而为,我们希望能够抓住这个机会,所以我最近一年的工作主要是将混沌工程这一技术在腾讯游戏落地。
一、什么是混沌工程
1、混沌工程的定义
混沌工程是为应对故障而生。大家知道我们运维人员都很辛苦,经常在周末或者半夜起来处理各种各样的故障。为了减少这种现象,更加有效地应对故障,混沌工程应运而生。
混沌工程是通过主动注入故障的方式,提前将系统的问题暴露出来,发现系统可能存在一些风险点,然后把这些问题提前解决掉。即使我们系统半夜或者周末发生故障,我们也可以安稳地休息。
上图中的内容是Netflix那本书中对混沌工程的定义,简单说就是通过主动注入故障的方式、提前发现问题,然后解决问题、规避风险。
2、混沌工程的作用
混沌工程的出现是为了有效应对故障,其作用具体可分为以下六点。
1)故障预防
混沌工程的核心点是预防故障,通过主动注入故障的方式将故障提前解决掉。
2)故障发现
混沌工程能够提前帮助我们检测故障。例如,我们通过混沌工程来检测我们的告警监控系统、舆情,定期巡检这些系统是否有效。通过注入故障验证系统的有效性,从而提高我们故障检测的速度,缩短故障平均检测时长。
3)故障响应
做混沌工程也可以加快我们的故障响应速度。例如,我们可能经常在下班之后做混沌工程,看我们团队的响应速度如何,是否在组织协调方面存在一些问题。这样能够提高我们整个团队的战斗力和故障响应的速度。
4)故障定位
混沌工程还可以帮我们定位故障。通过混沌工程可以判断故障是否能够及时被检测到;我们系统的一些巡检工具、Matrics、Log、Trace等可观测平台,它们的有效性是否可靠;我们的诊断工具是否能够能够及时定位到根因。这样可以加快我们故障定位的速度,提高效率。
5)故障恢复
发现故障后,我们要修复故障。我们通过混沌工程也可以检验故障切换、限流熔断、降级等策略以及应急预案是否有效,能不能快速地修复故障,缩短我们故障的平均修复时长,这也是我们做混沌工程的一个重要出发点。
6)复盘改进
故障结束之后,我们经常要对故障进行复盘。故障修复后,我们在生产环节很难复现。通过混沌工程我们可以非常简单高效地复盘我们项目已经发生过的一些故障,这也是混沌工程的一个重要作用。
综上所述,混沌工程通过提前主动注入故障、发现问题、解决问题的方式,降低我们生产环境中故障发生的概率。
二、混沌工程平台建设
具体到混沌工程的实践,业界有一套方法论。通过理解与总结,我把它分为5个环节。
要搞混沌工程,首先要有一个平台。这个平台可以做出故障、实现故障的编排、同步观测实验效果以及输出实验报告。完成实验之后发现、跟进、解决问题,将问题解决后再次提交验证,通过这一闭环,不断地提升业务的稳定性与可靠性,就是做混沌工程的核心理念。
在腾讯游戏的具体落地中,我们通过混沌实验的全生命周期来设计这一平台。
1、流程设计
1)实验前
做一个实验,首先要有创造、注入故障的能力,要有故障场景,这里的故障场景就是指故障原子。我们希望实验平台能够提供丰富的故障原子,将这些原子组合起来模拟出现网可能会发生的各种故障。
在实验过程中,实验平台要能够打通我们当前系统或公司已经存在的一些监控系统,例如一些基础监控,或者业务特性的指标监控,并将其对接集成到实验平台。
我们混沌实验平台还需要管理我们的实验目标。例如我们的一个K8S集群、一批IP或者一个物理机群等,要能够对靶点进行分类,对通常说的爆炸半径进行管理。接下来,我们要能够对实验做编排,通过一些拖拉拽的方式,将一次混沌实验编排进来,这是这个平台在实验前应具备的能力。
2)实验中
实验中,我们的核心点是希望平台能够注入故障,同时观察实验的效果,即一边做实验一边看效果。
实验的过程中可能会出现一些我们预料之外的异常情况,我们要有兜底的策略,能够在极端情况下自动停止实验。做到很好的实验防护,也是我们这个平台需要具备的能力之一。
我们还希望平台具有故障恢复的能力。做完实验后,现场环境就能够及时恢复。
3)实验后
实验结束之后,平台需要输出实验报告。实验发现的问题需要通过实验报告呈现出来。我们要对实验报告进行汇总分析,看是否发现了新问题、新隐患或新知识。我们得到结果要去分析,发现问题要去跟进,落实到人将问题处理掉。
我们还要进行大量的统计分析。例如游戏的的质量评分如何,英雄联盟手游最近上线,通过统计分析,它的得分非常高,稳定性和可靠性也非常好。
2、故障原子
混沌实验平台最核心的能力是故障注入,人为地制造各种各样的故障与破坏。
腾讯游戏主要使用自研的混沌工程引擎,以及引用一些其它的业界开源引擎。我们引用了Chaos Mesh等引擎来对我们的实验做集成。有了这些底层的引擎后,我们就获得了许多故障原子。
- 存储层面:Io高负载、Io延迟、Io错误、文件句柄耗尽等故障原子。
- 计算资源层面:CPU负载高、满载等故障原子。
- 网络层面:时延、丢包、乱序、重复,带宽满,端口耗尽等故障原子。
- 节点/容器层面:关机一分钟、删pod、杀容器、杀pod等故障原子。
- 应用层面:进程将死、进程崩溃、HTTP协议状态码错误等故障原子。
- 自定义:可以制定一个机器脚本,例如自己写一个shell脚本、Python脚本,或者go二进制包。上传这个包,我们可以对其注入故障,这样就可能对一些特殊的业务场景做定制化的开发。
基本上有了这些故障,我们在生产环境中或实验环境下,就可以通过随意的组合,模拟出现网各种各样的故障。
3、应用故障注入
推荐一下Chaos Mesh产品,它专门为K8S场景设计,可以模拟包括pod、网络、Io、内核等多种各层面的故障。我们使用了Chaos Mesh产品一年多,使用效果不错。有了这个工具,我们在K8S环境下就可以直接注入故障,成本较低。
我们在实验过程中发现,即使有了计算资源、网络等基础层面的故障原子,也不能完全满足需求。我们有时候要经常对服务做一些应用层面的故障原子。因为腾讯游戏的服务大部分走HTTPS协议,有时可能要去对服务的某一个路径、某一批用户或某一个大区的玩家等做故障实验,这时就要通过网关MESH这一流程来做这个实验。
我们服务架构上面的每一个服务前面都有一个网关,所有流量都会经过网关流到真正的后端服务。对网关下发指定或者遥测等是通过统一的平台实现的。
所有流量都会经过网关,那么网关就可以对流量做治理。很多公司应该都会采用这种架构对流量做治理,我们可以做流量的限速、降级、熔断等。除此之外,我们还可以对流量做一些劫持、二次处理,这也就是混沌工程可以做的事情。
具体来说,流量从网关进来后,我们可以修改它的状态码。例如本来的状态码是200,我们修改为4xx;或者可以注入一个延迟,把这个服务sleep一段时间之后再返回;再者我们还可以对Header做一些注入,对剥离做修改等,甚至对带宽做限制、对用户做过滤。这样的话混沌工程就可以在应用层面对玩家做故障注入了。
用传统的引擎做应用层面的故障注入成本很高,但是有了网关MESH能力,我们做故障注入的成本会非常低。
举个例子,我们想对某一个或某一批玩家做故障注入,配置起来很简单。我们只需要在平台上选择我们的实验对象,配置好规则并提交,实验就可以马上生效了。
这时我们就可以在客户端上,体验故障注入是否有效果,以及对玩家有何影响。这样做故障只影响到这一批玩家,对现网其他的玩家没有任何影响,我们的爆炸半径就可以得到很好的控制,故障范围、故障风险也可以得到一定把控,这也是网关MESH能够带来的收益。
4、实验编排
毫无疑问,故障注入是混沌工程的核心能力,但除了故障注入外,混沌实验平台还应该具备一边做实验一边观察效果的能力。
平台需要能够编排。现网的实验可能非常复杂,故障可能通过各种实验场景的组合才会复现或模拟出来,还有我们的实验目标、靶点、实验对象,我们要有一个地方将实验配置集成管控起来。
例如上图中,我们想把CPU烧到80%并持续10分钟,就可以通过这个表单提交。我们想延迟一秒并持续10分钟,也可以通过这个表单提交。
这样的话我们的实验目标、实验配置以及我们想要观察的稳态指标(做实验过程中想要同步观察的指标),都可以通过编排的方式串联起来。编排能力可以大大提高我们的实验效率,这个能力也是混沌工程实验平台必备的能力。
5、实验观测
有了编排,我们还希望在真正做实验时同步观察实验的效果。这个实验效果可能是来自一些基础监控平台的指标,例如最基础的一些IaaS层的监控;也可能是QPS、延迟、同时在线人数等相关的一些业务特性指标,这些指标混沌平台是没有的。
在腾讯游戏,我们将基础监控以及业务的一些特性监控打通、对接、集成,这些已经有的指标可以直接集成进来,没有的我们也提供了普通标识,用户可以直接把指标暴露出来,在平台配置采集规则,这样我们可以主动把用户的业务指标拉过来,从而实现在平台做实验时,同步观察这个实验对用户服务的影响。这一方法实现了整个指标透明化,是实验观测所获得的收益。
6、实验报告
做混沌工程,实际上有些类似于去医院做体检。去医院做体检之后,医院一般都会输出一个记录身体各种指标的报告。这些身体指标有没有超过健康的阈值,报告中都会有标记。医生发现参考值过高时,会提醒我们在相关方面多加注意,并提供一些建议,到下次体检时具体关注这些指标有没有改善。
做一次体检,我们最想获得的就是这个报告,这个报告能够体现出我们做体检的收益。做混沌工程也一样,我们做了混沌工程实验,到底有没有收益,有没有发现问题,要在报告中体现出来。
我们希望这个平台能够将整个实验过程中的一些历史数据、编排数据、稳态指标等数据永久持续化存储下来,这样的话,我们后续就可以随时回溯我们这个实验的过程数据。
有了数据之后,我们希望能够分析这些数据,发现问题。发现问题才是做混沌工程的目标。发现问题后,我们希望能够对问题进行分类,并把问题落实到具体的责任人,让他来跟进解决。这样的话,我们这个实验才会实现很好的闭环,也就是上文中提到的核心理念。不断地发现问题、解决问题,并且形成循环,这才是我们实验的初衷。
7、收益
做了这么多,有了故障原子、实验编排、实验报告,有什么收益呢?
大家也知道,没有提出混沌工程前,我们也会进行一些容灾演练,好像没有混沌平台也能够做这件事情。
经过实验,我们总结的收益点如上图所示。
没有混沌平台的时候,我们去做实验,要自己写脚本、写工具、开发工具、测试、编排,一个复杂场景可能要自己去串联。我们还要去执行、观察效果,效果数据可能分散在各种平台,我们可能要不断地通过在各种平台之间切换,才能看到实验的效果数据。一个故障演练下来至少是小时级以上的。
有了混沌实验平台,我们做实验的效率大大提升了。我们编排一个实验,编排它的靶点、实验配置、观测指标,几乎可以做到分钟级。几分钟时间,我们就可以把整个实验编排出来,然后一边做实验一边观察效果,同时去发现问题、分析问题,大大缩短了实验时间。
总结来说,降本增效就是做混沌平台收益点。
三、混沌工程实践
有了平台大家不一定使用,我们要进行实践。
实践的目标非常清晰,要提升我们基础设施、平台、业务与应用的可用性与稳定性,要检验组织的协同效率,检验组织的协作方式、流程是否合理。
我们有以下几个实践要点:
- 控制风险。
- 自动化实验。我们现在很多业务的版本迭代速度非常快,如果每发布一个版本,我们都要去跟进、做实验,会产生极高的人工成本,所以我们需要去做一些自动化的实验。
- 红蓝对抗。提升组织团队的协作能力。
1、控制风险
做混沌工程会对业务和系统产生破坏性。我们做混沌工程目的是通过主动输出故障,发现问题、解决问题,所以风险控制是非常必要的。
一些教材或者文章都推荐混沌工程要直接上生产,这个理论没有错,实验全部在生产环境上做,产生的报告是非常有说服力的。但在生产环境做实验,会带来很高的风险,也会产生极高的人力成本。如果哪一方没参与,他的服务出问题,可能就会导致现网的严重事故。实验一旦超出我们预想的情况,可能会造成业务方不可接受的损失。
1)风险控制
腾讯游戏的实践是每半年左右,在生产环境中做一次集中化的大规模混沌演练。更多的故障是在准生产环境(预发布环境)中进行。因为预发布环境与生产环境的配置基本相当,所以我们在准生产环境做实验,数据的可靠性也有一定保证。
实践过程中,我们发现很多问题都是在预发布环境中提前暴露的。我们在预发布环境发现了许多问题,这些问题都得到了提前的规避解决。
例如,游戏上都有体验服大区,我们在体验服中做实验只影响体验服的玩家,不会影响到现网的大批量玩家。所以一旦出问题,体验服的玩家会反映服务有问题,我们就可以立马发现系统的一些隐患。所以,我们很多的实践都在预发布环境中进行。我们还进行了自动化的实践,每次版本发布,我们会自动去执行混沌演练。
腾讯一般会有专门的演习环境,这个演习环境是跟现网完全隔离的,所有的人都可以在上面随时随地地发起混沌演练。这个演习环境非常方便我们的开发、测试以及运维同学去做演练。
目前来看,通过各个环境的管控,我们实验风险得到了较好的控制。
2)实验防护
光有实验风险的控制是不够的,我们希望有防护兜底的能力,包括我们的实验防护能力。
实验防护方面,我们的做法是基于稳态指标配置阈值。我们会采集业务的稳态指标,如果没有的话,我们会提供Prometheus,让用户主动上报稳态指标。我们基于稳态指标配置阈值,指标达到阈值后会触发告警,收到告警后会触发一个钩子,钩子会终止实验。这样的话,在极端情况下,实验就能够做到自动终止,从而有效控制风险。
2、自动化实验
上文中提到过游戏的版本,包括游戏商业化、活动部分,版本发布都非常快,可能隔一两天就会发布一个活动。如果每发布一个活动或者每迭代一个版本都要做一次混沌实验,成本会很高。所以我们把混沌实验和我们的DevOps流水线集成起来,开发同学每发布一次版本都会自动调用混沌平台的套餐去执行。这样的话,无论每次在何时何地发布版本,实验都会被自动地引用执行,大大降低了我们实验的人力成本,提高了实验效率。
3、红蓝对抗
做混沌工程的一个初衷是提升团队的响应、协同效率,也就是我们组织的战斗力。
事实上,一个团队想提高自己的效率是缺乏动力的。腾讯游戏的做法是进行红蓝对抗,一个团队对另外一个团队的服务做攻击、对抗,看这个团队的服务可靠性到底如何,然后把它的攻击结果在小的范围内公示出来,这样我们防守方自己的缺陷就会提前被暴露。红蓝对抗把混沌工程有效地在团队之间进行了落地。将这种方式运转起来,可以取得较好的收益。
4、实验内容
我们做了一年多的混沌实验,那么到底做了哪些实验呢?下图中抽象了一些具体的实验项目。
每个业务、系统都有自己的特性,上图中只是一些比较通用的项目。
1)单点故障
通过杀一台机器、杀pod、杀容器,检测故障隔离、准备切换、健康探针、探测等是否有效。
2)告警验证
通过实验触发告警,看告警能不能被有效地处理,来检测我们组织的响应机制。
3)强弱依赖
通过混沌工程发现强弱依赖不合理的关系。我们有时候会发现,一个配置管理端的故障可能导致现网的玩家访问出现问题,控制面影响到数据面极不合理。我们通过混沌工程可以检测到许多这种不合理的依赖关系,从而验证我们服务架构的合理性。
4)网络抖动
我们会经常在现网做一些网络抖动实验。用户访问我们的服务,链路是很长的,出现一些丢包、抖动是非常普遍的。所以测试我们的客户端或者整个架构,到底能不能容忍网络上的一些微小抖动,有没有快速失败、重试的策略,也是我们演练的一个重要目标。
5)机房故障
机房出现故障虽然是小概率事件,但还是有可能出现整个机房宕机、不可用的情况,我们要通过混沌工程去做一些整个机房不可用的实验,验证我们的服务是否具有异地容灾的能力。
6)第三方故障
我们会使用第三方服务,它的质量可能不受我们掌控。这些第三方服务是否具备降级、熔断这样的一些策略,不可控的话,本地是否有缓存等,这些都可以通过混沌工程来验证。
7)过载保护
一些黑产可能会对我们的服务进行一些恶意攻击,我们的混沌工程可以模拟攻击,主动去检测我们的服务是否具备防刷、流控等能力。
以上是比较通用的一些实验内容。当然每种业务都有自己的一些特性,这里不再一一赘述。互联网行业变化是永恒的,我们的架构版本一直在变化,我们这个平台也在不断迭代。上述只是我们最近一年的一些初步的实践经验。
>>>>
Q&A
Q:混沌工程不断地去制造故障,监控告警会不断被触发,你们是怎样在很短的时间内终止操作的?不可控故障马上自愈、监控马上恢复的流程可以分享一下吗?
A:这个点就是上面提到的实验防护能力。我们平台会采集包括业务的 QPS、延迟、同时在线人数等稳态指标。用户在做实验的时候,可以基于这些指标去配置告警阈值。比如我们的同时在线人数下降了20%,达到阈值,我们的故障防护策略就会生效。当然它不是立即的,可能会经过两个或者三个周期,比如连续三个周期之后,它才会真正地触发这一次实验的防护,把实验自动停止掉。