首页 > 解决方案 > .NET 微服务中的隔板示例

问题描述

在 Sam Newman 的“构建微服务”(O'Reilly)中,有一个名为Bulkheads的部分,该部分讨论了防止阻塞的微服务干扰整个系统的方法。

如本节所述,隔板的一个示例是具有单独的连接池来连接到每个下游服务。

作者谈论的是对下游服务的同步调用,所以我将以上内容理解为“HTTP 客户端池”。

但是,在 .NET 中,越来越多的人认为最佳实践是使用单例 HTTP 客户端来提高可伸缩性。

我是否直截了当地认为,在 .NET 中,这种隔板不适用?

如果有的话,我们应该更关注哪些其他类型的舱壁?

隔板页面

标签: .netarchitecturemicroservicesdotnet-httpclient

解决方案


我想解释一些事情,以便您可以全面了解这种模式。

套接字和 TCP

假设您有 3 项服务 A、B、C。在每个客户端请求上,您都需要使用 http 调用它们。每次创建 http 客户端时,都会在下面创建一个 tcp 连接并打开套接字。套接字的数量有硬性限制,如果你有非常多的 http 调用,你最终可能会吃掉所有的套接字连接。这就是为什么需要重用单个http客户端的原因。在 .net 核心中,您可以使用 HttpClientfactory 来实现这一点。因此,如果您有 3 个服务要通过 http 调用,您可以在下面打开 3 个单独的 http 连接(套接字),这些连接将被重用。

线程池

另一部分是关于线程池的。即使您使用共享/单例 http 客户端连接进行调用,您仍然必须为该连接分配线程。假设您总共有 100 个线程可用于满足客户端请求。任何超过 100 个请求的请求都会排队。现在假设您使用具有 100 个线程的连接池的 http 独立调用三个服务。在愉快的路径中,每个服务都会及时返回,当线程完成工作(http请求完成)时,它将返回池以完成队列中的下一个客户端请求。在这段时间里,100 个线程使用 3 个共享的 httpclient 实例来调用外部服务,并且下面只有 3 个套接字。所以直到这一点我们都很好。

失败的服务

现在让我们说一项服务要么很慢,要么很慢。由于线程池(在本例中为 100)是共享的,并且您正在调用慢/慢服务,但线程需要更长的时间来响应。其他 2 个服务仍然很好并且可以响应,但是由于服务降级,任何调用降级服务的线程都需要更长的时间才能完成请求,或者最终会在返回线程池之前超时。这意味着越来越多的 clinet 请求正在排队。此时,消费者对其他(健康)服务的请求会受到影响。最终消费者不能再向其他服务发送请求,而不仅仅是原来的无响应服务。您所有可用的线程都停留在降级的服务中,并且队列仍在增长。其他消费者不再能够消费该服务,导致级联故障效应。

舱壁救援

这是舱壁来救援的地方。根据使用者负载和可用性要求将服务实例划分为不同的组。这种设计有助于隔离故障,并允许您为某些消费者维持服务功能,即使在故障期间也是如此。

消费者还可以对资源进行分区,以确保用于调用一项服务的资源不会影响用于调用另一项服务的资源。例如,调用多个服务的消费者可能会为每个服务分配一个连接池。如果服务开始失败,它只会影响为该服务分配的连接池,允许消费者继续使用其他服务。

所以从上面的例子中你会说请为每个服务分配 33 个线程。现在失败的服务只会影响分配给它的线程。健康的服务将继续使用它们分配的线程而没有任何问题,并将继续满足客户端的请求。

.Net Core 和 Polly

Polly 是处理这类情况的非常著名的图书馆。Polly 自然适合 .Net Core,您可以将多个策略分配给包括隔板在内的 http 客户端。

您可以找到有关波利的更多信息 https://github.com/App-vNext/Polly

希望有帮助!


推荐阅读