通过混沌工程使微服务更具弹性

微服务已成为开发和部署服务的团队非常流行的模式。使用微服务为开发人员提供了更小、更集中的代码库,并且在部署服务的时间和方式上更加独立。与使用单体相比,这些是很大的优势。

但是,天下没有免费的午餐。当您从单体架构过渡到微服务时,复杂性并不会消失——它只是发生了一些变化。由于代码库较小,单个微服务的开发更加容易,但在生产中操作微服务可能会变得更加复杂。使用微服务构建的系统中可能会运行更多的主机和/或容器 – 更多的负载均衡器、更多的防火墙规则等。您可能会针对不同的微服务将 NGINX 用于不同的目的(Web 服务、反向代理、负载均衡)。当您从数十个服务增长到数百个甚至数千个服务时,它就会变得越来越重要。为了理解系统并预测其行为。此外,所有服务都通过网络相互通信,而不是通过单体应用内的模块间调用进行通信。

我们如何验证基于微服务的系统不仅可以在正常条件下按设计运行,而且还可以处理环境中的意外故障或性能下降?混沌工程是一种很好的方法。混沌工程是一种实践,可以帮助您的团队更好地管理在生产中运行的应用程序,并使您的系统更具弹性。

什么是混沌工程?

我们将混沌工程定义为深思熟虑、有计划的实验,旨在揭示我们系统中的弱点。我们经常使用的一个比喻是疫苗接种,即将一种潜在有害的物质注射到体内,以预防未来的感染。在混沌工程实验中,我们主动将故障“注入”到我们的系统中来测试他们的韧性。我们使用科学方法进行这些实验:形成假设,进行实验,看看它是否验证了假设。

我们可以注入系统的一些故障类型包括关闭主机或容器、增加 CPU 负载或内存压力以及增加网络延迟或数据包丢失。还有其他的,但这让您了解我们可以在实验中做什么样的事情。

形成假设

进行混沌工程实验的第一步是形成我们的假设。该假设描述了我们期望注入的故障对系统产生的影响。请记住,我们正在尝试测试我们系统的弹性。一般来说,我们的假设是系统能够适应我们注入的故障类型。但有时我们发现我们的假设并不正确,我们可以利用我们学到的知识来提高系统的弹性。

例如,假设我们在 NGINX 上运行一个无状态 HTTP 服务,该服务向我们的一些其他服务公开 REST API。我们在生产环境中的 10 台主机上运行此服务的实例,因为这是处理当前负载而不用尽每台主机上的 CPU 所需的数量。我们可以通过故意关闭主机来主动测试我们是否内置了足够的冗余。在这种情况下,我们的假设是“系统对主机故障具有弹性 – 不会对其他服务或使用该系统的人员产生影响。”然后我们可以进行实验来看看我们的假设是否正确。

爆炸半径、震级和中止条件

规划实验时要牢记的三个重要概念是爆炸半径、震级和中止条件。让我们仔细看看它们是什么。

爆炸半径是我们运行实验的主机(或容器)的比例。这是一个非常重要的合作因为我们需要尽量减少实验对用户的潜在影响,即使是在非生产环境中。我们的想法是,我们从一个小的爆炸半径开始(例如一个主机或容器),然后随着我们了解更多并熟悉实验而增加爆炸半径。

幅度是指我们对各个主机或容器施加的压力或干扰的大小。例如,如果我们正在测试对运行 NGINX 的 Web 服务器进行 CPU 攻击的效果,我们可能会首先增加 20% 的 CPU 负载(幅度),并随着时间的推移而增加。我们可以观察增加 CPU 负载对响应时间等服务指标的影响,以确定系统在性能变得不可接受之前可以承受多大的攻击。

中止条件是导致我们停止实验的条件。最好提前了解哪些类型(或数量)的系统影响会导致实验破坏性太大而无法继续。时间软管可能是错误率或延迟的增加,或者可能是监控软件生成的某种警报。您可以根据需要定义中止条件,这些定义可能因实验而异。

爆炸半径、震级和中止条件使我们能够安全地进行混沌工程实验。在我们计划混沌工程实验时,始终牢记系统的用户非常重要,这样我们就不会对他们产生负面影响。它们是我们努力使系统更具弹性并为他们提供更好的用户体验的原因。

通过黑洞攻击验证依赖关系

从整体迁移到微服务时,复杂性的增加之一是额外的依赖项。您现在拥有多个相互依赖的服务,而不是包含系统所有业务逻辑的单一应用程序。您的微服务还可能依赖于其他外部服务,例如 API来自您的云提供商或您用作基础架构一部分的 SaaS 服务。

当这些外部或内部依赖项失败时会发生什么?您在代码中设置的保护措施是否真的可以缓解这些故障?您的超时和重试逻辑之类的内容是否适合您的系统在生产中的实际运行方式?

黑洞攻击是测试您是否可以处理失败的依赖项的好方法。黑洞攻击会阻止主机或容器对特定主机名、IP 地址和/或端口的访问,以模拟该资源不可用时会发生的情况。这是模拟网络或防火墙相关中断以及网络分区的好方法。

在外部依赖项的情况下,假设我们正在运行一项使用 Twilio API 向客户发送 SMS 消息的服务。我们知道我们与 Twilio 的通信可能随时中断,因此我们设计了微服务来读取我的信息仅当它们通过 Twilio API 成功发送到 Twilio 后,才从队列中删除它们。如果 Twilio API 不可用,消息会在我们端排队(可能使用 Kafka 或 ActiveMQ 等消息总线),一旦恢复与 Twilio 的通信,它们最终将被发送。听起来不错,对吧?

但是,在我们实际测试之前,我们如何知道当我们与 Twilio 的网络连接被切断时,我们的服务实际表现如何?我们如何知道设计服务时在白板上绘制的内容就是它在生产中的实际运行方式?

通过运行黑洞攻击,我们阻止该服务对 Twilio API 的访问,我们可以看到它的实际行为。这可以帮助我们回答很多问题,例如:消息是否正确排队?我们设置的超时时间是否合适?随着消息队列的增长,服务是否继续表现良好?而不是查看代码并对答案进行有根据的猜测对于这些问题,我们实际上可以注入失败并看看会发生什么。

在这种情况下,我们的假设可能是,“消息在网络连接断开时正确排队,并在网络连接恢复时正确传送。”当我们进行黑洞攻击时,我们要么证明要么反驳这个假设。如果我们反驳它,我们可能会学到一些有助于使我们的系统更具弹性的东西。

黑洞攻击还可用于验证内部依赖项失败时会发生什么,并发现隐藏的依赖项。隐藏的依赖项是一个常见问题,在它们引发事件之前发现它们是很棒的事情。当有人添加对服务的新依赖项,但组织内没有很好地记录或沟通时,就会发生隐藏依赖项。例如:服务 A 已更新,现在它依赖于服务 B,但运营服务 B 的团队并不知道这一点。他们将服务 B 停机进行维护,突然之间服务 A 意外中断。如果服务 A 是一项关键服务(例如您的登录服务),或者是让客户购买商品的服务,那么这可能会造成代价高昂的中断。对于团队来说,这并不是一个罕见的问题,因为映射和可视化服务依赖关系可能很困难。

通过定期对您的服务运行黑洞攻击,您可以暴露这些隐藏的依赖关系,以便相关团队了解它们。您还可以获得我们讨论的外部依赖项的其他好处。您可以看到当您的服务所依赖的服务无法访问时,您的服务如何响应,您的超时和重试配置是否正确等等。您的基于微服务的分布式系统如何处理网络分区?黑洞攻击是找出答案的好方法。

结论

我们定义了混沌工程,并展示了它如何帮助您构建更具弹性的微服务架构。我们还讨论了使用黑洞攻击o 查看服务如何响应外部和内部依赖项故障。

黑洞攻击非常适合了解您的服务对依赖项故障的恢复能力,但您还可以在微服务环境中进行其他非常有用的实验。关闭主机、增加延迟或数据包丢失、破坏 DNS 解析以及增加 CPU 或内存压力都是测试微服务弹性的好方法。有关可在微服务上执行的混沌工程实验的更多想法,请查看 Gremlin 社区页面上的教程。

想要尝试使用 NGINX Plus 进行混沌工程吗?立即开始 30 天免费试用或联系我们讨论您的使用案例。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注