在Netflix,咱们发现主动的故障测试是一个很是棒的方法,帮助咱们在生产环境中发现潜在的问题,为咱们的用户提供了可靠的产品。算法
咱们作的全部努力(虽然有些是手动的),帮助咱们顺利地没有意外地度过了整个假期(若是在除夕之夜被选中值班,那就更好了!😊)。数据库
可是谁喜欢手动的工做呢?另外,咱们只测试预期的失败,每次练习一般只针对单个服务或组件进行测试。咱们要作得更好!json
想象一下,一只猴子在你的代码和基础架构中爬行,注入小的故障并检查其是否致使用户影响。segmentfault
在探索构建这种猴子的过程当中,咱们发现了由彼得·阿尔瓦罗(Peter Alvaro)开发的称为Molly的故障测试方法。(http://www.cs.berkeley.edu/~p...) 缓存
鉴于咱们已经有了一个称为FIT(Fault Injection Test)的故障注入服务,相信咱们能够在短时间内构建一个原型实现。(https://medium.com/@Netflix_T...)安全
咱们认为,把Molly论文中阐述的概念应用到大规模生产中,这很是有意义。所以,咱们与Peter取得了联系,了解他是否有兴趣共同构建原型。如下就是咱们的合做结果介绍。架构
“依赖树驱动的故障注入(LDFI)逆向地从正确的系统输出中,断定注入故障是否会改变输出结果。”
Molly首先查当作功请求的全部内容,而后问:“哪些因素会改变这个结果?” 咱们如下面这个简化的请求为例:框架
故障集: (A|R|P|B) 机器学习
一开始,咱们假设全部都是必要的因素。而后,假设用户影响是由A或R或P或B故障引发的,其中A表明API(其余以此类推)。咱们首先从潜在故障点中随机选择并从新执行该请求,并在选定点注入故障。微服务
三个潜在的结果:
在此示例中,评价(Ratings)故障,请求成功,从而生成了如下图表:
故障集: (A|P|B) & (A|P|B|R))
由此可了解该请求的更多信息和故障点状况。因为播放列表(Playlist)是一个潜在故障点,所以咱们接下来将其失效,生成如下图表:
故障集: (A|PF|B) & (A|P|B) & (A|P|B|R))
这说明了上面第三个潜在的结果。因为执行了故障接管操做(PlaylistFallback),该请求仍然成功。因此,咱们有了一个新的故障点须要探索,同时更新实验范围,并进行清理、注入并重复,直到没有更多的故障点可探索为止。
Molly对如何探索这个搜索空间没有规定。咱们的实现方式是:先列出故障点失效的全部可能性,而后从最小组合中随机选择。例如,[{A},{PF},{B},{P,PF},{R,A},{R,B}…]。
探索从全部单点故障开始:A,PF,B;而后继续两个故障的组合,依此类推。
Netflix请求的依赖树是什么?
利用链路跟踪系统,可为整个微服务构建请求依赖树。经过FIT,咱们可用“注入点”的方式得到更多信息。这些都是系统可能发生故障的关键拐点。
注入点,包括Hystrix命令执行、高速缓存查找、数据库查询、HTTP调用等等。
FIT提供的数据帮助咱们构建更完整的依赖树,这就是算法分析的输入。
在上面的示例中,咱们看到了简单的服务请求树。如下是是利用FIT数据扩展了的请求依赖树:
“成功”是什么?最重要的即是用户体验,须要一种衡量标准来反映这一点。为此,咱们利用了设备报告的指标集。经过分析这些指标,就能够肯定请求是否会产生用户影响。
另外一种更简单的方法是依靠HTTP状态代码肯定成功的结果。可是状态码可能会引发误解,由于某些框架在部分红功时就返回“200”的状态,而在请求内容才放置用户影响的错误描述。
目前,只有部分Netflix请求具备相应的设备报告指标。为更多请求类型添加设备报告的指标后,咱们就有机会扩展自动故障测试以覆盖更普遍的设备流量。
支持回放请求使Molly简单易用,但咱们目前作不到。在收到请求时不知道该请求是否等价,不知道是否能够安全地回放。
为了弥补这一点,咱们将请求分红多个等效类,每一个类中的请求“具备”相同的功能,即执行相同的依赖调用并以相同的方式失败。
为了定义请求类,咱们着重使用收到的请求信息:
咱们先尝试去查看这些请求功能和依赖项之间是否存在直接映射。事实并不是如此。接下来,咱们探索了使用机器学习来查找和建立这些映射的方法。这彷佛是有但愿的,可是须要大量的工做才能使其正确。
相反,咱们将范围缩小到只检查Falcor框架生成的请求。这些请求经过查询参数提供了一组json路径以供请求加载,即“视频”、“配置文件”、“图像”。咱们发现这些Falcor路径元素与加载这些元素所需的内部服务一致。
将来的工做须要找到一种更通用的方法来建立这些请求类别映射,以便咱们能够将测试范围扩展到Falcor请求以外。
这些请求类别,会随Netflix工程师编写和部署的代码而变化。为了抵消这种偏移,咱们会天天对设备报告的指标集进行抽样,对潜在的请求类别进行分析。无流量的旧类别使之过时,新的代码路径则建立新的类别。
请记住,此探索的目标是在故障影响大量用户以前找到它并修复。在运行咱们的测试时,引发大量用户影响,这是不可接受的。
为了减轻这种风险,咱们重塑了探索方式,实如今任何给定时间段内只进行少许实验。
每一个实验的范围都只针对一种请求类别,实验运行时间很短(20-30秒),受影响的用户数很小。
咱们但愿每一个实验至少有10个好的示例请求。
为了滤除误报,咱们会查看实验的整体成功率,超过75%请求的失败状况标记为已发现的失败。
因为咱们的请求类映射不是完美的,因此咱们还会过滤掉因为某种缘由没有执行要测试的失败请求。
假设咱们一天能够运行500个实验。若是咱们每次运行均可能影响10个用户,那么最坏的影响是天天有5,000个用户受到影响。
可是,并不是每一个实验都会致使失败。实际上,大多数实验都会成功。
若是10%的实验中发现失败(较高的估计值),那么实际上咱们天天会影响500个用户的请求,而重试能够进一步缓解。
当天天处理数十亿个请求时,这些实验的影响就很小了。
咱们很幸运,“App Boot”请求,做为最重要的Netflix请求之一,知足了咱们的探索标准。该请求会加载运行Netflix应用,以及用户视频初始列表所需的元数据。
对于Netflix而言,这是一个关键时刻,咱们但愿从一开始就向客户提供可靠体验来赢得他们。
这也是一个很是复杂的请求,涉及数十个内部服务和数百个潜在的故障点。
对这个空间的蛮力探索须要2^100次迭代(大约30个零),而咱们的方法可以在大约200次实验中对其进行探索,并从中发现了五种潜在的故障,其中一种是故障点的组合。
一旦发现故障,咱们该怎么办?
好吧,还得手动处理。咱们尚未达到能自动修复故障的地步。
在这种状况下,咱们有一个已知故障点的列表,以及一个容许某些人使用FIT重现故障的“方案”。由此,咱们能够验证故障并肯定解决方案。
咱们很高兴可以构建此原型实现,验证明施并使用它来发现真正的故障。
咱们也但愿可以扩展它,以自动方式搜索更多的Netflix请求空间,在真正的故障发生以前,找到更多会产生用户影响的潜在故障点,并解决它们!
来源:混沌工程实践
做者:三水蜗牛 原文做者:Kolton Andrus, Ben Schmaus
标题:Automated Failure Testing, aka Training Smarter Monkeys
出处:Netflix Technology Blog
声明:文章得到做者受权在IDCF社区公众号(devopshub)转发。优质内容共享给思否平台的技术同伴,如原做者有其余考虑请联系小编删除,致谢。
6月每周四晚8点,【冬哥有话说】开心一“夏”。公众号留言“开心”可获取地址