隔舱模式是一种可以承受故障的应用程序设计类型。 在隔舱体系结构(也称为基于单元的架构)中,应用程序的元素被隔离到池中,因此如果一个失败,其他元素将继续运行。 它以船体的分节隔板(隔舱)命名。 如果船体受到破坏,只有受损的分段才会进水,从而可以防止船只下沉。
上下文和问题
基于云的应用程序可以包含多个服务,其中每个服务具有一个或多个使用者。 服务过载或发生故障会影响服务的所有使用者。
此外,一个使用者可以使用每个请求的资源同时向多个服务发送请求。 当使用者向配置不当或无响应的服务发送请求时,可能无法及时释放客户端请求所用的资源。 随着不断地向服务发送请求,这些资源可能会耗尽。 例如,客户端的连接池可能会耗尽。 此时,使用者向其他服务发出的请求会受到影响。 最终,使用者不再能够向其他服务(而不仅仅是原始的无响应服务)发送请求。
资源耗尽问题同样会影响具有多个使用者的服务。 源自一个客户端的大量请求可能耗尽服务中的可用资源。 其他使用者不再能够使用该服务,从而导致连锁故障效应。
解决方案
根据使用者负载和可用性要求,将服务实例分区成不同的组。 此设计有助于隔离故障,即使在发生故障期间,也能为某些使用者保留服务功能。
使用者也可以将资源分区,确保用于调用一个服务的资源不会影响用于调用另一个服务的资源。 例如,对于调用多个服务的使用者,可为其分配每个服务的连接池。 如果某个服务开始发生故障,只有分配给该服务的连接池才会受到影响,因此,使用者可继续使用其他服务。
此模式的优势包括:
- 隔离使用者和服务,防止发生连锁故障。 可在使用者或服务自身的隔舱中隔离对其造成影响的问题,防止整个解决方案发生故障。
- 在发生服务故障时,可以保留一部分功能。 应用程序的其他服务和功能可继续工作。
- 可以部署能够为使用方应用程序提供不同服务质量的服务。 可以配置高优先级使用者池来利用高优先级服务。
下图显示了围绕调用单个服务的连接池构建的隔舱。 如果服务 A 发生故障或导致其他某种问题,该连接池将被隔离,因此,只有使用分配给服务 A 的线程池的工作负荷才受影响。 使用服务 B 和 C 的工作负载不受影响,可继续工作而不会中断。
下图显示了调用单个服务的多个客户端。 为每个客户端分配了独立的服务实例。 客户端 1 发出了过多的请求,使其实例近乎瘫痪。 由于每个服务实例相互隔离,其他客户端可继续发出调用。
问题和注意事项
- 围绕应用程序的业务和技术要求定义分区。
- 如果使用战术 DDD 设计微服务,则分区边界应与边界上下文保持一致。
- 将服务或使用者分区到隔舱时,请考虑相应技术提供的隔离级别,以及成本、性能和可管理性方面的开销。
- 考虑将隔舱与重试、断路器和限制模式合并,提供更周密的故障处理。
- 将使用者分区到隔舱时,请考虑使用进程、线程池和信号灯。 resilience4j 和 Polly 等项目提供了用于创建消费者隔舱的框架。
- 将服务分区到隔舱时,请考虑将这些服务部署到独立的虚拟机、容器或进程。 容器能够以相当低的开销合理平衡资源隔离。
- 使用异步消息通信的服务可以通过不同的队列集进行隔离。 每个队列可以包含专用的实例集用于处理该队列中的消息,或者包含单个实例组,以通过某种算法来取消排队和调度处理负载。
- 确定隔舱的粒度级。 例如,若要将租户分配到不同的分区,可将每个租户放入独立的分区,或者将多个租户放入一个分区。
- 监视每个分区的性能和 SLA。
何时使用此模式
使用此模式可以:
- 隔离使用一组后端服务所用的资源,尤其是应用程序可以提供某种功能级别时,即使某个服务未能响应。
- 将关键使用者与标准使用者相隔离。
- 防止应用程序发生连锁故障。
此模式可能不适用于以下情况:
- 项目中可能不接受资源的低效利用。
- 没有必要提高复杂性
工作负荷设计
架构师应评估如何在其工作负荷的设计中使用“隔板模式”,以解决 Azure Well-Architected Framework 支柱中涵盖的目标和原则。 例如:
支柱 | 此模式如何支持支柱目标 |
---|---|
可靠性设计决策有助于工作负荷在发生故障后复原,并确保它在发生故障后恢复到正常运行状态。 | 通过组件之间的有意和完全分段引入的故障隔离策略试图将故障仅控制在遇到问题的隔舱上,防止对其他隔舱产生影响。 - RE:02 关键流 - RE:07 自我保护 |
安全设计决策有助于确保工作负荷数据和系统的机密性、完整性和可用性。 | 组件之间的分段有助于将安全事件限制在遭到入侵的隔舱上。 - SE:04 分段 |
性能效率通过在缩放、数据和代码方面进行优化, 帮助工作负载高效地满足需求。 | 每个隔舱都可以单独扩展,以有效地满足封装在隔舱中的任务的需求。 - PE:02 容量规划 - PE:05 缩放和分区 |
与任何设计决策一样,请考虑对可能采用此模式引入的其他支柱的目标进行权衡。
示例
以下 Kubernetes 配置文件创建一个隔离的容器用于运行单个服务,该容器具有自身的 CPU 和内存资源与限制。
apiVersion: v1
kind: Pod
metadata:
name: drone-management
spec:
containers:
- name: drone-management-container
image: drone-service
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "1"