使用HttpClientFactory的.Net Core WCF连接池实现

我们的产品是在使用WCF 4.5与SOAP客户端服务进行交互的.Net Core 2.2平台上开发的。 在服务期间,数据总线开发人员注意到服务器上的高负载。 此外,访问服务的问题开始出现。 结果,发现原因在于活性化合物的数量。

存在连接耗尽的问题。 建立连接或限制与外部或内部服务的连接数时,可能是由于缺少可用端口而引起的。 有两种解决方案:

•增加可用资源,
•减少连接数。

第一种选择对我们不可用,因为只能在服务提供商方面增加资源。 因此,我们决定寻找优化化合物数量的选择。 在本文中,我们将讨论找到的解决方案。



主意


事实证明,问题在于,对于每个请求,我们都创建了WCF客户端的新实例。 这使得无法使用WCF中已经实现的连接池,因为为每个通道都创建了一个池,并且我们为每个请求都创建了一个新通道。 当然,您可以使用静态WCF客户端重写负责与WCF交互的服务。 但是在这种情况下,该池也将是静态的,这可能会导致DNS更改出现问题,如本文所述 。 它还讨论了解决方案-HttpClientFactory 。 该解决方案的实质是工厂可以使用自己的池,在该池中定期更新连接。 默认更新周期为两分钟,但可以更改。

在我们的产品中,我们已经使用HttpClientFactory与其他服务进行交互,并且在WCF中使用工厂似乎是静态WCF客户端的不错选择。 在这种情况下,我们不必更改WCF服务的实现。 但是他们可以使用工厂可以使用的池。 此外,它还使我们能够解决本文所述的 Linux中的NTLM身份验证问题,因为在配置http客户端时,您可以为消息处理程序设置身份验证方案。

实作


要使用HttpClientFactory,只需将客户端配置描述添加到ConfigureServices。 在这里,您可以使用自己的配置添加几个命名或键入的客户端。 在这种情况下,每个客户端将使用其自己的连接池。 在示例中,我们使用命名客户端。

services.AddHttpClient("ClientName"); 

在WCF中,您可以为http客户端添加自己的消息处理程序。 为此,将由方法初始化的委托添加到绑定参数。 在那里,作为输入参数,我们在WCF端创建了一个处理程序并返回我们自己的处理程序。 结果,从委托方法获得的处理程序将传递给WCF端的客户端http设计器。

因此,从工厂池返回处理程序时,我们将用它替换传入的处理程序。 要从工厂池中获取处理程序,我们使用HttpMessageHandlerFactory。 为了访问绑定参数,有必要实现一个从IEndpointBehavior继承的类。 然后将其添加到我们的WCF客户端。

在示意图上,在WCF端创建新客户端的算法如下所示。



我们实现CustomEndpointBehaviour。

 public class CustomEndpointBehavior : IEndpointBehavior { private readonly Func<HttpMessageHandler> _httpHandler; public CustomEndpointBehavior(IHttpMessageHandlerFactory factory) { //       _httpHandler = () => factory.CreateHandler("ClientName"); } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { //      bindingParameters.Add(new Func<HttpClientHandler, HttpMessageHandler>(handler => _httpHandler())); } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } } 

接下来,将我们的EndpointBehavior添加到WCF客户端。

 var httpMessageHandler = serviceProvider.GetRequiredService<IHttpMessageHandlerFactory>(); var client = new WcfClient(); client.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior(httpMessageHandler)); 

现在,当通过WCF创建连接时,将尽可能使用池中的处理程序实例。 这将减少活性化合物的数量。

测验


为了进行验证,我们发送了100个相同的请求。 结果,在没有池的情况下,化合物的峰达到53,而在没有池的情况下,化合物的峰不超过7。

监视没有池的连接:



监视池连接:



结论


True Engineering的我们在WCF中实现了一个连接池,它不依赖于与WCF客户端一起工作的实现。 它还有效地节省了运行应用程序的服务器端和服务提供者端的资源。

我们花了很多时间寻找优化选项,但是解决方案本身却变得简洁明了。 趁热拿走)

Source: https://habr.com/ru/post/zh-CN465255/


All Articles