正确实现HTTP连接池的方法

时间:2018-06-16 17:14:22

标签: java connection-pooling apache-httpclient-4.x resttemplate

我在REST API调用某些Web服务期间使用Apache HTTP Client进行连接池。

奇怪的是,尽管我使用HTTP连接池,但我的表现并没有增加。

我使用Apache HTTP Client连接到我的网络服务,代码如下documentation

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();

cm.setMaxTotal(200);

cm.setDefaultMaxPerRoute(20);

HttpHost host = new HttpHost("abc.com", 80);
cm.setMaxPerRoute(new HttpRoute(host), 50);

CloseableHttpClient httpClient = HttpClients.custom()
        .setConnectionManager(cm)
        .build();

我正在使用Spring的RestTemplate使用Spring HttpClient来围绕Apache的HttpComponentsClientHttpRequestFactory实现。

但即使我没有使用连接池,即。使用Spring的SimpleClientHttpRequestFactory,我没有任何性能优势。

我的连接仍需要相同的时间才能完成。

我所做的是实现HTTP连接池的正确方法吗?我做错了吗?

如果我方需要进一步的信息,请告诉我。

3 个答案:

答案 0 :(得分:2)

请注意HTTP客户端池的工作方式,可能会在短时间内提高性能。检查下面的分析:

来自PoolingHttpClientConnectionManager javadocs

  

版本4.4中更改了过时连接的处理。以前,代码会在重新使用之前默认检查每个连接。现在,代码仅检查连接,如果自上次使用连接以来经过的时间超过已设置的超时。默认超时设置为2000ms

从池性能角度来看,这意味着只要管理员默认在2秒的时间内将该路由视为“活动”,就会重用与特定路由的连接。 在2秒不活动之后,与该路由的连接将被视为过时并被丢弃,从而在下次请求该路由时引起连接初始惩罚。

换句话说,开箱即用,池可在2秒内提高连接后的连接性能。重型航线是最受益的。

作为一个简单的测试,将池大小设置为较小的值,例如5 max。在linux上发送5个请求并检查与该路由建立的连接数

watch "netstat -ant | grep <your route IP>"

你应该看到5个连接。等待10或20秒并向同一路径发送2个请求,您应该看到这5个连接已关闭,2个新连接已创建。 使用调试日志记录也可以观察到这一点。 Here是一篇很好的文章作为参考。

答案 1 :(得分:0)

我相信您正在正确设置HttpClients.custom()和池管理器。

我的实现有一点不同之处在于,我使用HttpClientBuilder.create()而不是RestTemplate,而是使用相同的方法调用。根据其他Stack Overflow answer,这不应该有所作为。

我之前在Spring应用程序中使用过此配置并且有很好的好处。我想知道是否反应发生得足够快,以至于你没有看到很大的好处?我能想到的另一件事是, namespace Server { class Program { static void Main(string[] args) { var namedPipeServerStream = new NamedPipeServerStream("myPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous); Task.Run(() => StartListeningAsync(namedPipeServerStream, (msg) => Console.WriteLine(msg))); Task.Run(() => SendMessageAsync(namedPipeServerStream)); Console.ReadLine(); } public static async Task SendMessageAsync(NamedPipeServerStream namedPipeServer) { using (var stream = new StreamWriter(namedPipeServer)) { while (true) { await Task.Delay(2000); try { var serialized = JsonConvert.SerializeObject($"Server {DateTime.Now}"); byte[] messageBytes = Encoding.UTF8.GetBytes(serialized); if (!namedPipeServer.IsConnected) { namedPipeServer.WaitForConnection(); Console.WriteLine("Client connected"); } await namedPipeServer.WriteAsync(messageBytes, 0, messageBytes.Length); await namedPipeServer.FlushAsync(); namedPipeServer.WaitForPipeDrain(); } catch (Exception exception) { Console.WriteLine($"Exception:{exception}"); } } } } public static async Task StartListeningAsync(NamedPipeServerStream namedPipeServer, Action<string> messageRecieved) { while (true) { try { StringBuilder messageBuilder = new StringBuilder(); string messageChunk = string.Empty; byte[] messageBuffer = new byte[1024]; do { if (!namedPipeServer.IsConnected) { namedPipeServer.WaitForConnection(); Console.WriteLine("Client connected"); } await namedPipeServer.ReadAsync(messageBuffer, 0, messageBuffer.Length); messageChunk = Encoding.UTF8.GetString(messageBuffer); messageBuilder.Append(messageChunk); messageBuffer = new byte[messageBuffer.Length]; } while (!namedPipeServer.IsMessageComplete); if (messageRecieved != null) { messageRecieved(JsonConvert.DeserializeObject<string>(messageBuilder.ToString())); } } catch (Exception exception) { Console.WriteLine($"Exception:{exception}"); } } } } } 可能无法正确配置。

答案 2 :(得分:0)

您的配置似乎是正确的。您可以使用多线程来使用系统资源来获得性能。

    HttpGet get = new HttpGet("http://www.codersjargon.com");

    PoolingHttpClientConnectionManager connManager 
      = new PoolingHttpClientConnectionManager();

    CloseableHttpClient client = HttpClients.custom().
        setConnectionManager(connManager).build();

     MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get);
     MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get);
     MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); 
     thread1.start();
     thread2.start();
     thread3.start(); 
     thread1.join(); 
     thread2.join();
     thread3.join();