如何在httpclient中设置TCP在java中保持活着

问题描述 投票:1回答:3

驻留在AWS私有子网中的我的Java应用程序通过AWS Nat网关连接到http服务器。我通过httpclient调用POST请求到HTTP服务器。该请求将需要10多分钟才能完成。我已经配置了一个套接字超时和1小时的连接超时,因为这是一个后台任务。但是中间AWS NAT网关将在300秒[5分钟]之后发送回RST数据包并导致连接被重置,我无法增加NAT网关超时。所以我需要从我的应用程序端处理这个问题。

我的策略是使用tcp保持活动时间,每隔240秒发送一个数据包以保持连接活动。我已将此配置如下

CloseableHttpClient httpClient = HttpClients.createDefault()
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 3600000); //connection Timeout
HttpConnectionParams.setSoTimeout(params, 3600000); // Socket Time out
HttpConnectionParams.setSoKeepalive(params, true); //Enable Socket level keep alive time

然后通过execute方法调用post请求

HttpPost post = new HttpPost("http://url");
HttpResponse response = httpClient.execute(post);

由于我使用的是Linux系统,我已经使用以下Sysctl值配置了服务器

sysctl -w net.ipv4.tcp_keepalive_time=240 
sysctl -w net.ipv4.tcp_keepalive_intvl=240
sysctl -w net.ipv4.tcp_keepalive_probes=10

但是在执行程序时,未启用保持活动状态,并且连接会像以前一样失败。

我用netstat -o选项检查了这一点,如下所示,保持活着状态

tcp        0      0 192.168.1.141:43770     public_ip:80          ESTABLISHED 18134/java           off (0.00/0/0)

有没有什么办法可以使用httpclient设置TCP保持活动的java代码。我也可以看到HttpConnectionParams已被弃用。但我找不到任何可以保持活着的新课程

谢谢

java apache-httpclient-4.x tcp-keepalive
3个回答
1
投票

我找到了解决问题的方法。好奇的情况是我无法使用httpclient中的某些构建器类来传递socket keep alive。我在问题中指定的一种方法是使用如下的HttpConnectionParams,但这不起作用,现在不推荐使用此类。

HttpParams params = httpClient.getParams();
HttpConnectionParams.setSoKeepalive(params, true);

因此,在检查apache http docs时,我可以看到现在连接参数通过RequestConfig类传递给httpclient。此类的构建器提供了设置connection_time_out和socket_time_out的解决方案。但是检查这个的社交代码我看不到启用SocketKeepAlive的选项,这就是我们想要的。所以唯一的解决方案是使用SocketBuilder类直接创建一个Socket并将其传递给HttpClientBuilder。

以下是工作代码

SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setSoTimeout(3600000).build(); //We need to set socket keep alive
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(3600000).build();
        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).
                                           setDefaultSocketConfig(socketConfig).build();
HttpPost post = new HttpPost(url.toString());
HttpResponse response = httpClient.execute(post);

在上面执行时,我可以看到在socket中根据我在linux内核中设置的sysctl值正确设置了keep alive

tcp        0      0 localip:48314     public_ip:443     ESTABLISHED 14863/java          keepalive (234.11/0/0)

如果某个人有更好的解决方案来从Requestconfig类或任何其他高级构建器类启用Socket Keep alive,我愿意接受建议。


0
投票

保持HTTP连接打开但长时间处于非活动状态是一个糟糕的设计选择。 HTTP是一种请求 - 响应协议,暗示请求和响应很快。

保持连接打开可以保存资源。从服务器(以及网络防火墙和路由器)的角度来看,打开连接并开始请求(在您的情况下为POST)但不会长时间发送任何字节的客户端与永远不会发送任何字节的客户端无法区分。更多数据,因为它有故障或恶意(进行DOS攻击)。服务器(和网络硬件)正确地得出结论,正确的做法是关闭连接并回收用于它的资源。您正试图与出于正当理由的正确行为作斗争。即使您设法解决TCP关闭问题,您也会发现其他问题,例如HTTP服务器超时和数据库超时。

您应该重新考虑两个组件之间的通信设计。也就是说,这看起来像是一个XY问题。你可能会考虑

  • 让客户端等到它在启动POST之前执行完整上载。
  • 将上传拆分为更小,更频繁的上传。
  • 使用HTTP以外的协议。

0
投票

使用Socket的上述方法可以很好地重置AWS网络负载均衡器超时之下的tcp_keepalive_intvl值。使用两者,重置允许java小时+连接的NLB tcp空闲超时。

© www.soinside.com 2019 - 2024. All rights reserved.