Bulkhead pattern - Azure Architecture Center | Microsoft Learn
Bulkhead模式是一种容错的应用程序设计类型。在隔离架构中,应用程序的元素被隔离到池中,这样即使其中一个出现故障,其他元素也可以继续工作。它是以船体的分段(舱壁)命名的。如果船体受损,只有受损部分充满水,从而防止船舶沉没。
背景和问题
- 基于云的应用程序可能包括多个服务,每个服务有一个或多个消费者。一个服务中的过度负载或故障将影响该服务的所有消费者。
- 此外,消费者可以同时向多个服务发送请求,为每个请求使用资源。当消费者向配置错误或没有响应的服务发送请求时,客户端请求所使用的资源可能无法及时释放。随着对服务的请求继续进行,这些资源可能会耗尽。例如,客户端的连接池可能已耗尽。此时,消费者对其他服务的请求将受到影响。最终,使用者不能再向其他服务发送请求,而不仅仅是最开始的那个的无响应服务。
- 同样的资源耗尽问题也会影响具有多个消费者的服务。来自一个客户机的大量请求可能耗尽服务中的可用资源。其他消费者不再能够使用该服务,从而导致级联故障效应。
解决办法
- 根据消费者负载和可用性需求,将服务实例划分为不同的组。这种设计有助于隔离故障,并允许您为某些消费者维持服务功能,即使在故障期间也是如此。
- 消费者还可以对资源进行分区,以确保用于调用一个服务的资源不会影响用于调用另一个服务的资源。例如,调用多个服务的消费者可能会为每个服务分配一个连接池。如果服务开始失败,它只影响为该服务分配的连接池,允许消费者继续使用其他服务。
- 这种模式的好处包括:
- 将消费者和服务与级联故障隔离开来。可以将影响消费者或服务的问题隔离在自己的隔板内,从而防止整个服务失败。
- 允许您在服务发生故障时保留一些功能。应用程序的其他服务和功能将继续工作。
- 允许您部署为消费应用程序提供不同服务质量的服务。高优先级使用者池可以配置为使用高优先级服务。
- 下图显示了围绕调用各个服务的连接池构建的隔离。如果服务A失败或导致其他问题,连接池将被隔离,因此只有使用分配给服务A的线程池的工作负载才会受到影响。使用服务B和C的工作负载不受影响,可以不中断地继续工作
- 下一个图显示了多个客户端调用单个服务。每个客户端分配一个单独的服务实例。客户机1发出了太多请求,使其实例不堪重负。由于每个服务实例都与其他服务实例隔离,因此其他客户端可以继续进行调用
问题和考虑
- 围绕应用程序的业务和技术需求去定义分区。
- 在将隔离服务或消费者时,要考虑技术提供的隔离级别以及成本、性能和可管理性方面的开销。
- 考虑将隔离与重试、断路器和节流模式结合起来,以提供更复杂的故障处理。
- 在将消费者隔离时,请考虑使用进程、线程池和信号量。像resilience4j(https://github.com/resilience4j/resilience4j)和Polly(https://github.com/App-vNext/Polly)这样的项目为创建消费者隔板提供了一个框架。
- 在将服务隔离时,请考虑将它们部署到单独的虚拟机、容器或进程中。容器以相当低的开销很好地平衡了资源隔离。
- 使用异步消息进行通信的服务可以通过不同的队列集进行隔离。每个队列可以有一组专用的实例来处理队列上的消息,也可以有一组实例使用一种算法来出列和发送处理。
- 确定隔离的粒度级别。例如,如果希望跨区分配租户,可以将每个租户放在单独的分区中,或者将多个租户放在一个分区中。
- 监控每个分区的性能和SLA。
什么时候使用
- 隔离用于使用一组后端服务的资源,特别是如果应用程序可以提供某种级别的功能,即使其中一个服务没有响应。
- 将关键消费者与标准消费者隔离开来。
- 保护应用程序免受级联故障的影响。
不适用
- 在项目中,资源的低效率使用可能是不可接受的。
- 增加的复杂性是不必要的。
举例
下面的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"
相关
Circuit Breaker pattern
Retry pattern
Throttling pattern
欢迎大家留言沟通