我已经在生产中使用了apache httpclient 4.5一段时间了,但最近,添加了一个新的用例,系统开始失败。
我们有多个通过REST Web服务进行通信的服务,客户端是apache httpclient 4.5的包装。
假设我有服务A与服务B通信。通信正常工作,直到我重新启动服务B.由于超时,我从服务A发起到服务B的下一个呼叫失败。在做了一些研究后,我发现基础性TCP连接因性能原因而被重用(不再有2路握手等)。由于服务器已重新启动,因此底层TCP连接已失效。
阅读完文档后,我发现在 n 秒后我可以使连接失效。假设我重启服务B,那么第一个 n 秒的呼叫将失败,但之后重建连接。这是我实施的keepAliveStrategy
connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(100);
connManager.setDefaultMaxPerRoute(10);
ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
long keepAliveDuration = super.getKeepAliveDuration(response, context);
if (keepAliveDuration == -1) {
keepAliveDuration = 45 * 1000; // 45 seconds
}
return keepAliveDuration;
}
};
CloseableHttpClient closeableHttpClient = HttpClients.custom()
.setConnectionManager(connManager)
.setKeepAliveStrategy(keepAliveStrategy)
.build();
我只是想知道这是否正确使用了这个库。我这就是它的工作方式,还是我让一切都变得过于复杂?
答案 0 :(得分:2)
不确定这是100%相同的情况,但这是我的2美分:
我们遇到了类似的问题(在一段时间不活动后,池中的连接断开)。当我们使用旧版本的HttpClient(3.X)时,我们使用了http.connection.stalecheck
管理器参数,当使用已关闭服务器端的连接时,获得IOException的可能性略有下降
升级到4.4+
后,这种方法已被弃用并开始使用setValidateAfterInactivity
,这是每次调用验证和运行时错误情景之间的中间点:
PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager();
poolingConnManager.setValidateAfterInactivity(5000);
void o.a.h.i.c.PoolingHttpClientConnectionManager.setValidateAfterInactivity(int ms)
定义不活动的时间段(以毫秒为单位),之后必须在将租用连接到消费者之前重新验证持久连接。传递给此方法的非正值会禁用连接验证。此检查有助于检测已变为陈旧(半关闭)的连接,同时在池中保持不活动状态。
如果您还控制使用的API,则可以将保持活动策略调整为客户端使用的时间。我们正在使用AWS Cloudfront + ELB来解除注册实例的连接耗尽,以确保在执行滚动升级时保持活动连接完全关闭。我想只要保证连接保持活动,比如30秒,传递给下面的连接管理器的任何值将始终确保有效性检查将减轻任何与陈旧/过期纯粹相关的运行时I / O错误连接。