什么是混沌工程?
《混沌工程原理》中这样定义:“混沌工程(Chaos Engineering)是在分布式系统上进行实验的学科, 目的是建立对系统抵御生产环境中失控条件的能力以及信心。”简而言之,混沌工程就是“故意破坏事物”的特殊方法,通过在生产环境中捣乱。比如随机重启生产环境中的服务器等,以发现生产环境中可能出现的隐藏问题;通过不断修复系统的缺陷,从而使系统更健壮、更具容错能力。
这里强调的是混沌工程并不仅仅是“搞破坏”,因为搞破坏非常容易,但在搞完破坏后,能不能有效控制破坏的爆炸半径,能不能有效控制对用户造成的影响,以及判断该问题是否需要修复并寻找修复方法......这些才是混沌工程中最关键的。
混沌工程和传统测试有很多重叠的部分。混沌工程应该成为传统测试的补充,是经过传统测试后系统已经足够稳定,可以在生产环境中被任意“破坏”,来进一步增强系统的稳定性的工程。由于需要生产环境中的真实场景,这类测试是不能通过单元测试和集成测试来模拟的。混沌工程的核心思想是以可控的方式主动注入故障,以验证系统的行为是否符合我们的预期,并在不正常的情况下进行修复,以此提高系统的稳定性。
为什么要实施混沌工程?
混沌工程可以主动测试生产环境中各种压力下的行为。通过比较假设行为和实际行为,我们可以在系统出现故障之前发现问题并修复问题。混沌工程可以做以下几件事情:
- 对软件和基础设施进行比传统形式更广泛的测试和验证;
- 发现传统测试无法发现的问题;
- 帮助团队了解系统在真实生产环境中的行为,服务如何被中断以及都有哪些Bug?
因此,混沌工程可以帮助我们增强系统的稳定性和可靠性,带来更好的用户体验。
如何实施混沌工程?
建立基线指标
在进行混沌工程实验之前,要先收集一组基线指标数据。这些指标包含基础设施的监控指标、告警指标、严重级别指标、应用程序指标等。下面介绍下这些指标的内容。
- 基础设施的监控指标:包含服务器的CPU 峰值、IO峰值、磁盘使用率、内存使用率,网络的延迟、数据丢包率、DNS 等指标。
- 告警指标:可以按服务统计每周的告警数量,处理告警的时间,以及每种服务每周最频繁的告警类型。
- 严重级别指标:可以按服务统计每周不同严重级别的事件数量,以及按服务统计每种严重级别的 MTTD(平均检测时间)、MTTR(平均故障恢复时间)和MTBF(平均故障间隔时间)。
- 应用指标:应用程序的可观察性指标,事件数量,请求的响应时间,数据库连接数,QPS(每秒查询数量),TPS(每秒事务数量)。
模拟真实事件
在生产系统中模拟真实事件来进行实验,有两种方式:攻击和场景。
- 攻击:将故障注入系统中,如消耗计算资源、关闭系统、丢弃网络包等方法,攻击是单个的故障注入方式。
- 场景:是将一组攻击保存的集合。场景中的攻击按顺序执行,可以更好地控制攻击的执行方式,并可以模拟较为复杂的故障。保存下来的场景可以被重复执行,并能够观察系统随着时间的行为变化。
不管使用哪种方式,在执行完成后,需要记录上述指标的观察结果并与基线进行比较。
分析结果
基于从实验中获得的结果数据与假设进行比较,并得出结论。这里有几个问题需要给出答案:
- 系统行为是否符合预期?
- 如果系统有监控告警等系统,是否按预期运行?
- 本次实验发现了哪些新问题?
- 告警系统多长时间检测到问题并发出通知?该时间是否可以接收?
- 实验结束后,系统是否自动恢复到正常状态?还是需要人工干预?
重复实验
修复问题后,重复执行该实验以确保问题得到彻底解决。如果系统成功抵御了攻击,说明该问题已经被修复。此时,应该考虑增加攻击的程度,爆炸半径或者一次性攻击目标的系统数量。这对于测试集群系统、自动扩展系统或负载均衡系统比较有用。
自动化实验
一旦系统能够抵御该攻击,就可以按照常规测试惯例定期执行攻击。可以将该实验的执行嵌入到 CI/CD 流水线中,这样有利于新的变更不会引起新的可靠性问题。下图显示了可以在软件生命周期中执行不同类型的混沌实验的各个阶段。只要有设计良好的混沌实验,就可以在每次执行流水线时都会执行这些混沌实验。这一步的目的是通过在生产之前或者在生产中引起问题之前发现实际问题。
混沌工程案例
SpringBoot 集成 ChaosMonkey
Netflix 不仅制定了《混沌工程原理》,还提供了一个将理论付出实际的强大工具:ChaosMonkey。ChaosMonkey 是一种工具,该工具会随机终止生产环境中运行的虚拟机实例和容器,使工程师能够构建更加弹性的服务。Spring Boot 是目前构建 Java 后台应用程序最受欢迎的框架。Spring Boot Chaos Monkey 是一个依赖库,可以将混沌工程的实践集成到 Spring Boot 的应用中。只需要下面两步就可以将 Chaos Monkey 添加的应用程序中。
STEP 1:在应用程序中添加 ChaosMonkey 的依赖包。
<dependency> <groupId>de.codecentric</groupId> <artifactId>chaos-monkey-spring-boot</artifactId> <version>2.2.0</version> </dependency>
STEP 2:在启动应用程序的时候,需要激活 chaos-monkey的profile 来初始化 ChaosMonkey。
java -jar chaosmonkeyforspringboot.jar --spring.profiles.active=chaos-monkey
启动后,就会在控制台中打印出 Chaos Moneky 的字样。
ChaosMonkey 配置
Chaos Monkey 在引入后并未开启,需要通过 chaos.monkey.enabled 配置项来开启。Chaos Monkey 提供了四种不同的攻击方式:
- 延迟攻击;
- 异常攻击;
- 杀掉应用程序攻击;
- 内存攻击。
这种攻击的开启和关闭可以通过下面四个配置项决定,并且每种攻击方式也有相应的配置参数。比如,延迟攻击是在每个请求处理时添加随机的延迟时间,该值由 chaos.monkey.assaults.latency-range-start 和chaos.monkey.assaults.latency-range-end 两个参数的区间值来设置。
chaos.monkey.assaults.latency-active=true chaos.monkey.assaults.exceptions-active=true chaos.monkey.assaults.memory-active=true chaos.monkey.assaults.kill-application-active=true
ChaosMonkey 的配置项清单可以通过 Spring Boot Actuator 的访问端口查看,首先需要通过下面两个配置项开启并将 chaosmonkey 添加到暴露的端口列表中。
management.endpoint.chaosmonkey.enabled=true management.endpoints.web.exposure.include=health,info,chaosmonkey
测试示例项目
在 Chaos Monkey 的设置里开启 chaos.monkey.assaults.exceptions-active=true,添加一个测试的 Controller 类,如下:
"/v1/test/chaosmonkey") ( public class OrderController { private OrderMapper orderMapper; "/orders") ( public List<Order> getOrders() { try { return orderMapper.selectAll(); } catch (Exception e) { e.printStackTrace(); return null; } } }
当调用该接口时,会随机产生异常。下图是使用 postman 批量调用该接口产生的结果,可以看出该接口执行了 10 次,其中成功 8 次,失败 2 次。这 2 次失败就是因为 Chaos Monkey 导致的。
混沌工程的落地离不开工具或平台,Spring Boot Chaos Monkey 是一个不错的开源项目,可以应用在企业内部的故障演练中,暴露服务本身以及服务与服务之间的调用问题,提升系统的健壮性。