【韧性架构设计】分布式系统的韧性

简介: 【韧性架构设计】分布式系统的韧性

由许多协同工作的微服务组成的云原生应用程序架构形成了一个分布式系统。确保分布式系统可用——减少其停机时间——需要提高系统的弹性。弹性是使用提高可用性的策略。弹性策略的示例包括负载平衡、超时和自动重试、截止日期和断路器。


弹性可以通过不止一种方式添加到分布式系统中。例如,让每个微服务的代码都包含对具有弹性功能的代码库的调用,或者让特殊的网络代理处理微服务请求和回复。弹性的最终目标是确保特定微服务实例的故障或降级不会导致导致整个分布式系统停机的级联故障。

在分布式系统的上下文中,弹性是指分布式系统能够在不利情况发生时自动适应以继续服务于其目的。

术语“可用性”和“弹性”具有不同的含义。可用性是分布式系统启动的时间百分比。弹性是使用策略来提高分布式系统的可用性。

弹性的主要目标之一是防止一个微服务实例的问题导致更多问题,这些问题升级并最终导致分布式系统故障。这被称为级联故障。

弹性策略

分布式系统的弹性策略通常用于 OSI 模型的多个层,如图所示。例如,物理和数据链路层(第 1 层和第 2 层)涉及物理网络组件,例如与 Internet 的连接,因此数据中心和云服务提供商将负责为这些层选择和实施弹性策略。

应用层是应用驻留的地方;这是人类用户(以及其他应用程序)直接与之交互的层。应用程序级(第 7 层)弹性策略内置于微服务本身。组织的开发人员可以设计和编写应用程序,使其在降级状态下继续工作,提供重要功能,即使其他功能由于一个或多个微服务的错误、妥协或其他问题而失败。

在流行的视频流应用程序的推荐功能中可以看到此类功能的一个示例。大多数时候主页包含个性化推荐,但如果相关的后端组件出现故障,则会显示一系列通用推荐。此故障不会影响您搜索和播放视频的能力。

传输层(第 4 层)提供网络通信能力,例如确保可靠的通信传输。网络级弹性策略在第 4 层工作,以监控每个微服务已部署实例的网络性能,并将微服务使用请求定向到最佳实例。例如,如果某个特定的微服务实例由于其所在位置的故障(例如网络中断)而停止响应请求,则新请求将自动定向到该微服务的其他实例。

将云原生应用程序部署为分布式系统的组织应考虑网络和/或应用程序级别的弹性策略。在这里,我们将研究云原生应用程序的四种此类策略:

  • 负载均衡
  • 超时和自动重试
  • 截止日期
  • 断路器

负载平衡、超时和自动重试支持分布式系统组件的冗余。截止日期和断路器有助于减少分布式系统任何部分的降级或故障的影响。

负载均衡

云原生应用程序的负载平衡可以在 OSI 模型的多个层执行。就像我们刚刚讨论的弹性策略一样,负载平衡可以在第 4 层(网络或连接级别)或第 7 层(应用程序级别)执行。

对于 Kubernetes,第 4 层负载均衡默认使用 kube-proxy 实现。它在网络连接级别平衡负载。Pod IP 地址的管理和虚拟/物理网络适配器之间的流量路由是通过容器网络接口 (CNI) 实现或覆盖网络(例如 Calico 或 Weave Net)来处理的。

回到第 4 层负载均衡,假设一个网络连接每秒向一个应用程序发送一百万个请求,而另一个网络连接每秒向同一个应用程序发送一个请求。负载均衡器不知道这种差异;它只看到两个连接。如果它将第一个连接发送到一个微服务实例,并将第二个连接发送到第二个微服务实例,它会认为负载是平衡的。

第 7 层负载平衡基于请求本身,而不是连接。第 7 层负载均衡器可以看到连接中的请求,并将每个请求发送到最佳微服务实例,这可以提供比第 4 层负载均衡器更好的均衡。一般来说,当我们说“负载平衡”时,我们指的是第 7 层负载平衡。此外,虽然第 7 层负载均衡可以应用于服务或微服务,但这里我们只关注将其应用于微服务。

对于云原生应用程序,负载平衡是指在微服务的运行实例之间平衡应用程序的请求。负载均衡假设每个微服务有多个实例;每个实例都有多个实例提供了冗余。只要可行,实例都是分布式的,因此如果特定服务器甚至站点出现故障,并非任何微服务的所有实例都将变得不可用。

理想情况下,每个微服务都应该有足够的实例,这样即使发生故障(例如站点中断),每个微服务仍然有足够的可用实例,以便分布式系统继续为当时需要它的所有人正常运行。

负载平衡算法

有许多用于执行负载平衡的算法。让我们仔细看看其中的三个。

  • 轮询是最简单的算法。每个微服务的实例轮流处理请求。例如,如果微服务 A 有三个实例——1、2 和 3——第一个请求将发送到实例 1,第二个发送到实例 2,第三个发送到实例 3。一旦每个微服务收到请求,下一个请求将分配给实例 1 以开始另一个循环通过实例。
  • 最少请求是一种负载均衡算法,它将新请求分发给当时待处理请求最少的微服务实例。例如,假设微服务 B 有四个实例,实例 1、2 和 3 现在分别处理 10 个请求,但实例 4 只处理两个请求。使用最小请求算法,下一个请求将转到实例 4。
  • 会话亲和性,也称为粘性会话,是一种尝试将会话中的所有请求发送到相同微服务实例的算法。例如,如果用户 Z 正在使用一个应用程序并导致请求被发送到微服务 C 的实例 1,那么在同一用户会话中对微服务 C 的所有其他请求都将被定向到实例 1。

这些算法有许多变体——例如,加权通常被添加到循环和最小请求算法中,这样一些微服务实例接收的请求份额比其他微服务实例更大或更小。例如,您可能希望支持通常比其他人更快地处理请求的微服务实例。

在实践中,单独的负载平衡算法通常不能提供足够的弹性。例如,它们会继续向已经失败且不再响应请求的微服务实例发送请求。这就是添加超时和自动重试等策略的好处。

超时和自动重试

超时是任何分布式系统的基本概念。如果系统的一部分发出请求,而另一部分在一定时间内未能处理该请求,则请求超时。然后,请求者可以使用系统故障部分的冗余实例自动重试请求。

对于微服务,在两个微服务之间建立并强制执行超时。如果微服务 A 的实例向微服务 B 的实例发出请求,而微服务 B 的实例没有及时处理,则请求超时。然后,微服务 A 实例可以使用微服务 B 的不同实例自动重试请求。

无法保证在超时后重试请求会成功。例如,如果微服务 B 的所有实例都有相同的问题,则对其中任何一个的请求都可能失败。但是,如果只有一些实例受到影响——例如,一个数据中心的中断——那么重试很可能会成功。

此外,请求不应总是自动重试。一个常见的原因是避免意外复制已经成功的事务。假设从微服务 A 到微服务 B 的请求被 B 成功处理,但它对 A 的回复延迟或丢失。在某些情况下可以重新发出此请求,但在其他情况下则不行。

  • 安全事务是相同请求导致相同结果的事务。这类似于 HTTP 中的 GET 请求。GET 是一个安全事务,因为它从服务器检索数据但不会导致服务器上的数据被更改。多次读取相同的数据是安全的,因此重新发出安全事务的请求应该没问题。安全事务也称为幂等事务。
  • 不安全的事务是相同请求导致不同结果的事务。例如,在 HTTP 中,POST 和 PUT 请求是潜在的不安全事务,因为它们将数据发送到服务器。复制请求可能会导致服务器不止一次地接收该数据并可能不止一次地处理它。如果交易正在授权付款或订单,您当然不希望它发生太多次。

截止日期

除了超时,分布式系统还有所谓的分布式超时,或者更常见的是截止日期。这些涉及系统的两个以上部分。假设有四个相互依赖的微服务:A 向 B 发送请求,B 对其进行处理并将自己的请求发送给 C,C 对其进行处理并向 D 发送请求。回复以另一种方式流动,从 D 流向 C ,C 到 B,B 到 A。

下图描述了这种情况。假设微服务 A 需要在 2.0 秒内回复其请求。在最后期限内,完成请求的剩余时间与中间请求一起移动。这使每个微服务能够优先处理它收到的每个请求,并且当它联系下一个微服务时,它会通知该微服务剩余的时间。

断路器

超时和截止日期分别处理分布式系统中的每个请求和回复。断路器对分布式系统有更多的“全局”视图。如果一个特定的微服务实例没有回复请求或者回复请求的速度比预期的慢,那么断路器可能会导致后续请求被发送到其他实例。

断路器通过为单个微服务实例设置服务降级或故障程度的限制来工作。当实例超过该级别时,会触发断路器并导致微服务实例暂时停止使用。

断路器的目标是防止一个微服务实例的问题对其他微服务产生负面影响并可能导致级联故障。问题解决后,可以再次使用微服务实例。

级联故障通常是由于针对经历降级或故障的微服务实例的自动重试而开始的。假设您有一个微服务实例,请求不堪重负,导致它响应缓慢。如果断路器检测到这一点并暂时阻止新请求进入实例,则实例有机会赶上其请求并恢复。

但是,如果断路器不动作并且新请求继续发送到实例,则该实例可能会完全失败。这会强制所有请求转到其他实例。如果这些实例已经接近容量,新请求也可能使它们不堪重负并最终导致它们失败。这个循环继续下去,最终整个分布式系统都失败了。

使用库实施弹性策略

到目前为止,我们已经讨论了几种弹性策略,包括三种形式的负载平衡加上超时和自动重试、截止日期和断路器。现在是时候开始考虑如何实施这些策略了。

首次部署微服务时,实施弹性策略的最常见方法是让每个微服务使用支持一个或多个策略的标准库。Hystrix 就是一个例子,它是一个为分布式系统添加弹性特性的开源库。由 Netflix 开发到 2018 年,Hystrix 调用可以包裹在一个微服务中依赖于另一个微服务请求的任何调用。弹性库的另一个示例是 Resilience4j,它旨在用于使用 Java 进行函数式编程。

通过应用程序库实施弹性策略当然是可行的,但它并不适用于所有情况。弹性库是特定于语言的,微服务开发人员通常为每个微服务使用最好的语言,因此弹性库可能不支持所有必要的语言。为了使用弹性库,开发人员可能必须使用提供不理想性能或具有其他重大缺陷的语言编写一些微服务。

另一个问题是依赖库意味着为每个微服务中的每个易受攻击的调用添加调用包装器。一些调用可能会丢失,一些包装可能包含错误——让所有微服务的所有开发人员一致地做事情是一个挑战。还有维护问题——未来每个从事微服务工作的新开发人员都必须了解调用包装器。

使用代理实施弹性策略

随着时间的推移,基于库的弹性策略实现已被基于代理的实现所取代。

一般来说,代理位于两方之间的通信中间,并为这些通信提供某种服务。代理通常在两方之间提供某种程度的分离。例如,A 方向 B 方发出请求,但该请求实际上是从 A 发送到代理,代理处理该请求并将自己的请求发送给 B。A 和 B 不直接相互通信。

下图显示了这种通信流程的示例。一个会话发生在微服务 A 的实例及其代理之间,一个单独的会话发生在 A 的代理和微服务 B 的实例之间。A 到代理和代理到 B 会话共同提供 A 和B.

在分布式系统中,代理可以在微服务实例之间实现弹性策略。继续前面的示例,当微服务 A 的实例向微服务 B 发送请求时,该请求实际上会发送到代理。代理会处理 A 的请求并决定它应该转到哪个微服务 B 的实例,然后它会代表 A 发出请求。

代理会监视来自 B 实例的回复,如果没有及时收到回复,它可以自动使用不同的微服务 B 实例重试请求。图中,微服务 A 的代理有微服务 B 的三个实例可供选择,它选择了第三个。如果第三个实例的响应速度不够快,则代理可以使用第一个或第二个实例来代替。

基于代理的弹性的主要优点是无需修改单个微服务即可使用特殊库;任何微服务都可以被代理。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
6月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1067 3
|
10月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
362 5
|
5月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的"神经网络",强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
存储 缓存 NoSQL
分布式系统架构8:分布式缓存
本文介绍了分布式缓存的理论知识及Redis集群的应用,探讨了AP与CP的区别,Redis作为AP系统具备高性能和高可用性但不保证强一致性。文章还讲解了透明多级缓存(TMC)的概念及其优缺点,并详细分析了memcached和Redis的分布式实现方案。此外,针对缓存穿透、击穿、雪崩和污染等常见问题提供了应对策略,强调了Cache Aside模式在解决数据一致性方面的作用。最后指出,面试中关于缓存的问题多围绕Redis展开,建议深入学习相关知识点。
815 8
|
9月前
|
监控 Linux 应用服务中间件
Linux多节点多硬盘部署MinIO:分布式MinIO集群部署指南搭建高可用架构实践
通过以上步骤,已成功基于已有的 MinIO 服务,扩展为一个 MinIO 集群。该集群具有高可用性和容错性,适合生产环境使用。如果有任何问题,请检查日志或参考MinIO 官方文档。作者联系方式vx:2743642415。
3160 57
|
11月前
|
消息中间件 人工智能 监控
文生图架构设计原来如此简单之分布式服务
想象一下,当成千上万的用户同时要求AI画图,如何公平高效地处理这些请求?文生图/图生图大模型的架构设计看似复杂,实则遵循简单而有效的原则:合理排队、分工明确、防患未然。
433 14
文生图架构设计原来如此简单之分布式服务
|
9月前
|
消息中间件 缓存 算法
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
670 0
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
|
11月前
|
并行计算 PyTorch 算法框架/工具
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
本文探讨了如何通过技术手段混合使用AMD与NVIDIA GPU集群以支持PyTorch分布式训练。面对CUDA与ROCm框架互操作性不足的问题,文章提出利用UCC和UCX等统一通信框架实现高效数据传输,并在异构Kubernetes集群中部署任务。通过解决轻度与强度异构环境下的挑战,如计算能力不平衡、内存容量差异及通信性能优化,文章展示了如何无需重构代码即可充分利用异构硬件资源。尽管存在RDMA验证不足、通信性能次优等局限性,但该方案为最大化GPU资源利用率、降低供应商锁定提供了可行路径。源代码已公开,供读者参考实践。
1012 3
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
|
11月前
|
人工智能 运维 监控
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。
|
存储 Prometheus Cloud Native
分布式系统架构6:链路追踪
本文深入探讨了分布式系统中的链路追踪理论,涵盖追踪与跨度的概念、追踪系统的模块划分及数据收集的三种方式。链路追踪旨在解决复杂分布式系统中请求流转路径不清晰的问题,帮助快速定位故障和性能瓶颈。文中介绍了基于日志、服务探针和边车代理的数据收集方法,并简述了OpenTracing、OpenCensus和OpenTelemetry等链路追踪协议的发展历程及其特点。通过理解这些概念,可以更好地掌握开源链路追踪框架的使用。
1307 41

热门文章

最新文章