混沌工程实践经验:如何让系统在生产环境中稳定可靠

阅读数:1625 2018 年 8 月 22 日 18:25

当你还是个孩子的时候,是否曾经为了了解某些东西的内部原理而故意把它们大卸八块?我们都这样做过。而在今天,我们把这种行为称为混沌工程。

作为开发者,我们的主要目标之一是开发稳定、安全且无错误的软件。为了实现这些目标,我们进行单元测试和集成测试,以便发现不可预期的行为,并确保我们测试的模式不会导致错误。现今的软件架构通常都包含了很多组件,单元和集成测试无法完全覆盖到这些组件。我们没注意到的一些服务器和组件在出现故障时仍然有可能将整个系统拖入深渊。

不是由你来选择那一刻,而是那一刻来选择你!

你只能选择为之做好准备。

——消防队长 Mike Burtch

背景简介

近年来,Netflix 一直是混沌工程背后的驱动者之一,极大地促进了混沌工程在分布式系统中的重要性。安全研究员 Kyle Kingsbury 采用了略微不同的方法,对分布式数据库、分布式队列和其他分布式系统的厂商所做出的承诺进行了验证。他使用 Jepsen 探测了上述系统的行为,得出了一些可怕的结论。你可以在 YouTube 上找到有关这个主题的演讲视频。

在本文中,我将对混沌工程做一个简单贴切的介绍。

不要低估了混沌工程社交性的一面,混沌工程不仅是关于如何摧毁某些东西,更重要的是把正确的人聚集在一起,共同创建稳定且容错的软件。

基础

我们在开发新的或已有的软件时,会通过各种形式的测试来增强实现。我们经常使用测试金字塔来表示应该要进行什么类型的测试以及做到怎样的程度。

混沌工程实践经验:如何让系统在生产环境中稳定可靠

测试金字塔说明了一种两难的境地:越是上层的测试,就会耗费越多的精力、时间和成本。

单元测试

我们通过单元测试来检验软件的预期行为。我们在没有依赖关系的情况下单独测试组件,并借助各种桩(mock)来控制它们的行为。这类测试不能保证它们是没有错误的。如果模块的开发人员在实现组件时犯了逻辑错误,那么这个错误也会在测试中出现——即使开发人员是先写的测试后写的代码。极限编程是解决这类问题的一种方式,在极限编程中开发人员在代码和测试之间不断交替。

混沌工程实践经验:如何让系统在生产环境中稳定可靠

集成测试

为了让开发人员和利益相关者能够与家人和朋友共度更多的空闲时间和轻松的周末,我们在编写完单元测试之后再编写集成测试。集成测试用于测试各个组件之间的交互。理想情况下,在成功运行单元测试并测试了相互依赖的组件之后,集成测试会自动运行。

混沌工程实践经验:如何让系统在生产环境中稳定可靠

得益于高测试覆盖率和自动化,我们的应用程序达到了非常稳定的状态,但在通往胜境的路上,相信每个人都体验过那种不愉快的感觉。我的意思是,我们的软件必须在生产环境中展示它真实的一面,看看它究竟有多好。只有在真实的条件下,我们才能看到每个组件的真实行为。而现代微服务架构的采用毫无疑问加重了这种不愉快的感觉。

软件架构的侵蚀

在松散耦合的微服务时代,软件架构可以使用“分布式系统”这个词来概括。各个系统都很好理解:它们可以进行快速的部署和扩展。但在大多数情况下,这会导致如下所示的架构:

混沌工程实践经验:如何让系统在生产环境中稳定可靠

我喜欢架构图,因为它们为我们提供了清晰而抽象的软件视图。然而,它们也可能将所有邪恶的陷阱和错误隐藏起来。它们特别擅长模糊底层和硬件。在现实生产环境中,以下架构图更接近现状:

混沌工程实践经验:如何让系统在生产环境中稳定可靠

因为防火墙规则的存在,负载均衡器不知道网关的所有实例或无法通过网络访问它们。有几个应用程序已经崩溃,但服务发现并未发现故障。此外,服务发现无法同步并提供不一样的结果。由于缺少服务实例,负载无法被分配,导致各个节点上的负载不断增加。为什么十二小时的批次作业必须在白天运行,而且为什么需要十二个小时?!

我相信你也有过类似的经历。你或许知道处理有缺陷的硬件、有问题的虚拟化、被错误配置的防火墙或进行公司内部繁琐的协调将意味着什么。

有时候,人们在讨论问题时会冒出这样的话:“这里没有出现混沌,一切都按照惯常的方式运作”。可能你很难相信,整个行业就是通过销售 ticket 系统而存活下来,这样我们就可以控制和记录混沌。下面的这句电影台词可以用来描述我们的日常生活:

混沌是驱动世界发展的引擎。

API 天堂 vs 后端地狱

API 试图要建立一个完美的世界,让我们通过调用定义好输入和输出的 API 获得我们需要的东西。我们使用了无数的 API,从而避免与地狱(后端或 API 实现)直接发生交互。我们实现了无数个抽象层,而冥王哈迪斯在这中间肆无忌惮地实施他的恶作剧。他的任务就是确保每一个 API 调用都受影响。好吧,我有点夸张了,但你们应该知道我想要说什么。

Netflix 展示了这将导致怎样的后果,所以让我们快速浏览一下它们的架构,以便更好地理解现代微服务架构的潜在复杂性。以下图片来自 2013 年纽约 QCon 大会的演讲:

混沌工程实践经验:如何让系统在生产环境中稳定可靠

更令人印象深刻的是,Netflix 的架构可以很好地运行,并对所有可能的错误做出反应。如果你观看 Netflix 开发人员的演讲,你会听到他们说“没有人知道它的工作原理,也没人知道为什么会这样”。这种洞见让混沌工程在 Netflix 生机勃勃。

不要随意尝试

在开始你的第一个混沌实验之前,请确保你的服务已经应用了弹性模式,并准备好处理可能出现的错误。

混沌工程不是制造问题,而是揭示问题。

——Nora Jones,Netflix 高级混沌工程师

正如 Netflix 的 Nora Jones 所指出的那样,混沌工程不是要制造混乱,而是要防止混乱。所以,如果你想要开始你的混沌实验,从小处开始,提前问自己以下问题:

混沌工程实践经验:如何让系统在生产环境中稳定可靠

如果你的基础设施——尤其是你的服务——没有为此做好准备,那么进行混沌实验是没有意义的。请记住这一点,现在我们现在开始进入混沌工程。

混沌工程规则

  1. 提前与你的同事讨论混沌实验计划!
  2. 如果你知道你的混沌实验将失败,请不要这样做!
  3. 混沌不应该让人感到意外,你的目的是证明假设。
  4. 混沌工程可帮助你更好地了解你的分布式系统。
  5. 控制混沌实验的影响范围。
  6. 在混沌实验期间控制好局面!

混沌工程原则

在混沌工程中,你应该完成下面描述的五个阶段,并始终控制好你的实验。从小处开始,并保持实验只有小范围的潜在影响。拔掉某处的插头,看看将要发生的哪些事情与混沌工程完全无关!我们不会制造不可控的混沌,反而要积极争取防止它们。

我强烈推荐 PrinciplesOfChaos.org 网站和免费电子书“Chaos Engineering(混沌工程)”。

混沌工程的阶段

混沌工程实践经验:如何让系统在生产环境中稳定可靠

稳定状态

最好先定义指标,让指标告诉你有关系统整体状态的可靠信息。在混沌实验期间,必须持续监控这些指标。当然,你也可以额外在实验之外监控这些指标。

指标可以是技术指标或业务指标——我认为业务指标比技术指标更重要。Netflix 在混沌实验期间监控用户成功播放视频的点击次数,这是他们的核心指标,属于业务领域。无法播放视频会直接到影响客户满意度。例如,如果你经营了一个在线商店,成功订单的数量或放置在购物篮中的商品数量将是重要的业务指标。

假设

事先想好应该发生什么情况,然后通过实验进行验证。如果你的假设无效,你必须根据调查结果找出错误,并将其提交给团队或公司。有时候,要做到完全不归咎责任是很困难的!作为一名混沌工程师,你的目标是了解系统的行为并向开发人员展示这些知识。这就是为什么要让每个人都尽早参到你的实验中。

现实世界中的事件

在现实生活中,有哪些问题正等待着我们?可能会发生什么样的新问题,哪些问题已经毁了我们之前的周末?在一个可控的实验中,我们必须先想清楚这些问题。

可能的例子包括:

  • Kafka 群集中的节点故障
  • 网络数据包丢失
  • 硬件错误
  • JVM 的 max-heap-size 参数设置不妥当
  • 延迟增加
  • 错误的响应

你可以随意往这个清单里添加其他的东西,只要始终与所选的架构紧密相关。即使你的应用程序不是由著名的云提供商托管,你自己公司的数据中心也会出现问题。我猜你一定能说出点东西来!

混沌实验示例

假设我们有几个通过 REST API 进行交互的微服务,并且使用了服务发现。为了以防万一,“产品服务”为“仓库服务”中的库存维护了一个本地缓存。如果仓库服务未在 500 毫秒内做出响应,则应使用缓存中的数据。我们可以在 Java 环境中实现这种行为,例如使用 Hystrix 或 resilience4j。因为有了这些库,我们可以非常轻松地实现回退和其他弹性模式。

环境

混沌工程实践经验:如何让系统在生产环境中稳定可靠

你将在下面找到一个成功的实验所需要的信息。

目标

仓库服务

实验类型

延迟

假设

由于调用仓库服务的延迟增加,因此 30%的请求使用了产品服务本地缓存中的数据。

影响范围

产品服务和仓库服务

之前的状态

OK

之后的状态

ERROR

结果

产品服务回退失败并导致异常,因为缓存无法对所有请求做出响应。

从结果中可以看出,我们使用了弹性模式,但仍然存在错误。必须通过再次运行实验来消除和测试这些错误。

自动化实验

混沌工程必须持续运行,你的系统也在不断变化:新版本进入生产环境、硬件更新、防火墙规则调整、服务器重新启动。最好的做法是在公司里建立混沌工程文化,并把它深植于每一位员工的心中。Netflix 通过让 Simian Army(Netflix 开源的测试套件工具,其中就包含了 Chaos Monkey)在生产环境中“肆意糟蹋”开发人员的产品来实现这一目标。虽然他们后来决定只在工作时间做这些事情,但总归有在做。

环境

对于第一次混沌实验,请选择与生产环境相同的环境。在风平浪静且与生产环境没有任何关联的测试环境中,你将无法获得任何有意义的结果。一旦你获得了初步结果并进行了改进,就可以继续进入生产环境,并在那里进行实验。混沌工程的目标是在生产环境中运行,并始终控制好局面,不要影响到用户。

开始混沌工程的第一步

起初,我很难在日常生活中理解和探索混沌工程的思想,毕竟我不是 Netflix、谷歌、Facebook 或优步的高级混沌工程师,况且我的客户才刚刚开始实施微服务。不过,我几乎总能找到 Spring Boot 的身影!有时是独立的应用,有时被部署在 Docker 容器中。我在技术大会上使用的演示总是至少包含一个 Spring Boot 应用程序。这导致了 Chaos Monkey for Spring Boot 的诞生,我们可以用它攻击现有的 Spring Boot 应用程序,而无需修改任何代码。

Chaos Monkey for Spring Boot

有关 Chaos Monkey for Spring Boot 将如何帮助你获得稳定的 Spring Boot 基础设施的所有相关信息,请访问 GitHub。

结论

我希望这篇文章能够帮助你理解混沌工程背后的理念和原则。混沌工程非常重要,即使我们不在 Netflix 工作,仍然有很多工作要做。我热爱我的工作,但更重要的是,我热爱与家人和朋友在一起的生活。我不想花费无数个夜晚和周末来修复严重故障,混沌工程让我们对我们的系统能够更好地应对生产环境中的恶劣条件充满了信心。

相关链接:

Jepsen: https://jepsen.io

Kyle Kingsbury 的演讲视频: https://www.youtube.com/watch?v=eSaFVX4izsQ

混沌工程电子书: https://www.oreilly.com/webops-perf/free/chaos-engineering.csp

Hystrix: https://github.com/Netflix/Hystrix

Resilience4j: https://github.com/resilience4j/resilience4j

Chaos Monkey for Spring Boot: https://codecentric.github.io/chaos-monkey-spring-boot

英文原文: https://blog.codecentric.de/en/2018/07/chaos-engineering/

感谢张婵对本文的审校。

收藏

评论

微博

用户头像
发表评论

注册/登录 InfoQ 发表评论