最近看到 Netflix 的混沌工程的介绍,感触颇深。在 TiDB 里面,我们为了保证系统的健壮性,也做了很多工作。在内部我们开始叫做 stability test,后来进化成 Schodinger 平台。之前我一直苦于没有没法对我们做得工作进行归类,毕竟它可能是一个 test,但又比 test 做得多一点,现在知道,原来我们一直做的其实算是一门工程实践。
既然是工程,那么就会有方法论,也就能详细的归纳总结出来实施的步骤,这样后面的同学就能非常快速的学习掌握,而不会像我们之前那么漫无目的的探索了,但我们现在还做不到这一步,而且相比 Netflix,我们还有很多路要走。所以我打算深入研究下 Netflix 是如何做的,在想想如何提升我们自己的工作。
首先,我们需要知道,混沌工程到底是什么。根据 Netflix 的解释,混沌工程师通过应用一些经验探索的原则,来学习观察系统是如何反应的。这就跟科学家做实验去学习物理定律一样,混沌工程师通过做实验去了解系统。
image.png
上图就是混沌工程的典型代表 - 猴子。拜 Netflix 所赐,现在大部分的混沌工程项目都叫做 Monkey,也就是一只讨厌的猴子,在你的系统里面上蹦下窜,不停捣乱,直到搞挂你的系统。
然后,我们需要知道,为什么需要混沌工程。应用混沌工程能提升整个系统的弹性。通过设计并且进行混沌实验,我们可以了解到系统脆弱的一面,在还没出现对用户造成伤害之前,我们就能主动发现这些问题。
混沌工程其实是很重要的,但我之前一直以为混沌工程就是测试,但它们还是有区别的。虽然混沌工程跟传统测试通常都会共用很多测试工具的,譬如都会使用错误注入工具,但混沌工程是通过实践对系统有更新的认知,而传统测试则是使用特定方式对某一块进行特定测试。譬如在传统测试里面,我们可以写一个断言,我们给定特定的条件,产生一个特定的输出,如果不满足断言条件,测试就出错了,这个其实是具有很明确的特性。但混沌工程是试验,而试验会有怎样的新信息生成,我们是不确定的。譬如我们可以进行下面的这些试验:
这些试验到底会有什么样的结果,有些我们可以预料,但有些可能我们就不会预先知道,只有发生了,才会恍然大悟,有一种『喔,这也会出现!』的感叹。
在开始应用混沌工程之前,我们必须确保系统是弹性的,也就是当出现了系统错误我们的整个系统还能正常工作。如果不能确保,我们就需要先考虑提升整个系统的健壮性了,因为混沌工程主要是用来发现系统未知的脆弱一面的,如果我们知道应用混沌工程能导致显而易见的问题,那其实就没必要应用了。
虽然 chaos 有混乱的意思,但混沌工程并不是制造混乱。相反,我们可以认为混沌工程是用经验的方法来定位问题的一门实验学科。譬如,我们可以思考:『如果我们在系统里面注入混乱了,这个系统会怎样?』,或者『我们系统离混乱的边界还有多远?』。所以,为了更好的进行混沌试验,我们需要有一些原则来进行指导。
在一个复杂系统里面,我们有特别多的组件,有很多不同的输入输出,我们需要有一个通用的方式来区别系统哪些行为是可以接受的,而哪一些则是不合适的。我们可以认为当系统处于正常操作时候的状态就是稳定状态。
通常我们可以通过自己测试,来确定一个系统的稳定状态,但这个方法当然是比较低效的,另一种更常用的做法就是收集 metric 信息,不光需要系统的 metric,也需要服务自身的 metric,但收集 metric 需要注意实时性的问题,你如果收集一个每月汇总的 metric 信息,其实没啥用,毕竟系统是实时变化的。现在市面上面有很多不错的开源 metric 系统,譬如我们就在用的 Prometheus。
当我们能收集到信息之后,就需要用这些信息去描述一个稳定状态。这个难度比较大,因为不同的业务是不一样的,即使是同一个业务,不同时间也可能变化很大。但也有一些方法,譬如我们可以根据前面一段时间譬如上周的 metric 的曲线得到一个大概合理的稳定状态,也可以自己做很多压力测试,得到相关的数据。
当有了 metric 以及知道稳定状态对应的 metric 是怎样之后,我们就可以通过这些来考虑混沌实验了。思考当我们注入不同的事件到系统中的时候,稳定状态会如何变化,然后我们就会开始做实验来验证这个假设。
在真实的世界中,我们可能遇到各种各样的问题,譬如:
做混沌试验的时候需要模拟这些故障,来看系统的状态。但从成本上面考虑,我们并不需要模拟所有的故障,仅仅需要考虑那些会比较频繁发生,而且模拟之后会很有效果的。在 TiDB 里面,我们主要就是模拟的网络,文件系统的故障,但现在看起来还是不够,后面会逐渐的添加更多。
要看混沌试验有没有效果,在真实生产环境中进行验证是最好的方法。但我相信大部分的厂商还没这么大的魄力,这方面 Netflix 就做的很猛,他们竟然能够直接停掉 Amazon 上面的一个 Zone。
如果不能再生产环境中试验,一个可选的方法就是做 shadow,也就是通常的录制生产环境的流量,然后在测试中重放。或者模拟生产环境,自己造数据测试。
最开始执行混沌试验,我们可能就是人工进行,试验进行的过程中,看 metric,试验结束之后,通过收集的 metric 在对比,看系统的状态。这个过程后面完全可以做成自动化的,也就是定期执行,或者系统发布的时候执行等。
如果能做到自动化执行试验,已经很不错了,但我们可以做的更多,甚至有可能根据系统的状态自动化的生成相关的试验,这个 Netflix 已经做了很多研究,但我们这边还处于初级阶段,没考虑过自动化生成的问题。
在进行混沌试验的时候,一定要注意影响的范围,如果没预估好,把整个服务搞挂了,导致所有的用户都没法使用,这个问题还是很严重的。
通常都会使用一种 Canary 的方法,也就是类似 A/B 测试,或者灰度发布这种的,在 Canary 集群这边做很多试验。也就是说,如果真的搞坏了,那也只是一小部分用户被搞坏了,损失会小很多。
在 Canary 里面还有一个好处,因为我们知道整个系统的稳定状态,即使不做混沌测试,也可以观察 Canary 里面的状态是不是跟之前的稳定状态一致的,如果不一致,那也可能有问题。
上面我们说了相关的原则,那么如何开始进行一次混沌试验呢?其实很简单,只要做到如下步骤就可以:
譬如对于 TiDB 来说,譬如我们可以选择验证网络隔离对系统的影响,我们会:
上面只是一个简单的例子,实际还会复杂很多,但通过这种方式做了操作了很多次之后,大家都会更加熟悉自己的系统。
这里在简单说说混沌成熟度模型,Netflix 总结了两个维度,一个是复杂度,一个就是接受度。前者表示的是混沌工程能有多复杂,而后者则表示的是混沌工程被团队的接受程度。
复杂度分为几个阶段:
初级
简单
复杂
高级
而接受度也有几个阶段:
在暗处
有投入
接受
文化
如果按照这上面两个维度来看,我们其实做的并不好,所以还有很大的提升空间。
摘自:https://www.jianshu.com/p/4bd4f88e24e4