Mar*_*rga 30 java rest spring http apache-httpcomponents
我有一个非常快速的RESTful服务.我在localhost上测试它.客户端正在使用Spring REST模板.我开始使用一种天真的方法:
RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));
Result result = restTemplate.postForObject(url, payload, Result.class);
Run Code Online (Sandbox Code Playgroud)
当我提出很多这些请求时,我收到以下异常:
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myservice":No buffer space available (maximum connections reached?): connect; nested exception is java.net.SocketException: No buffer space available (maximum connections reached?): connect
Run Code Online (Sandbox Code Playgroud)
这是由连接未关闭并挂在TIME_WAIT状态引起的.当短暂的端口耗尽时,异常开始发生.然后执行等待端口再次空闲.我看到长时间休息的高峰表现.我得到的速度几乎是我所需要的,但当然,这些TIME_WAIT连接并不好.在Linux(Ubuntu 14)和Windows(7)上进行了测试,由于端口的不同范围,在不同时间得到了类似的结果.
为了解决这个问题,我尝试使用HttpClient和Apache Http Components库中的HttpClientBuilder.
RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));
HttpClient httpClient = HttpClientBuilder.create()
.setMaxConnTotal(TOTAL)
.setMaxConnPerRoute(PER_ROUTE)
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
Result result = restTemplate.postForObject(url, payload, Result.class);
Run Code Online (Sandbox Code Playgroud)
有了这个客户,我看到没有例外.客户端现在只使用非常有限数量的短暂端口.但无论我使用什么设置(TOTAL和PER_ROUTE),我都无法获得所需的性能.
使用该netstat命令,我发现服务器连接的次数不多.我尝试将数字设置为数千,但似乎客户端从未使用过那么多.
如果不打开太多连接,我能做些什么来提高性能?
更新:我已经尝试将总路由和每个路由连接的数量设置为5000和2500,但它仍然看起来客户端不会创建超过一百(从判断netstat -n | wc -l).REST服务使用JAX-RS实现并在Jetty上运行.
UPDATE2:我现在已经调整了服务器的一些内存设置,我的吞吐量非常好.天真的方法仍然有点快,但我认为这只是客户端池的一小部分开销.
Col*_*n M 38
实际上Spring Boot没有泄漏连接.您在这里看到的是Linux内核(以及每个主要操作系统)的标准行为.从机器关闭的所有插座都会TIME_WAIT持续一段时间.这是为了防止使用该临时端口的下一个套接字接收实际用于该端口上的前一个套接字的数据包.您在两者之间看到的差异是每个人采用的连接池方法的结果.
更具体地说,默认情况下RestTemplate 不使用连接池.这意味着每个休息呼叫都会打开一个新的本地临时端口和一个到服务器的新连接.如果您的服务非常快,它将立即吹过其可用的本地端口范围.使用Apache HttpClient,您可以利用连接池.这将阻止您的应用程序看到您描述的问题.但是,鉴于您的服务响应速度比Linux内核更快地响应TIME_WAIT,连接池将使您的客户端变慢,无论您做什么(如果它没有减慢任何速度 - 那么你就会用完当地短暂的港口再次).
虽然可以在Linux内核中启用TCP重用,但它可能会变得危险(数据包可能会延迟,您可能会得到短暂的端口接收他们不理解的随机数据包,这可能导致各种问题).这里的解决方案是使用第二个示例中的连接池,具有足够高的数字以实现接近您正在寻找的性能.
为了帮助您调整连接池,您需要调整maxConnPerRoute和maxConnTotal参数.maxConnPerRoute限制将对单个IP:端口对maxTotal进行的连接数,并限制将要打开的总连接数.在您的情况下,由于看起来所有请求都发送到同一位置,您可以将它们设置为相同(高)值.