通过 AWS Nat 网关的连接问题
Connection issues through AWS Nat Gateway
我有一个 Amazon Linux 2 应用程序服务器,在私有子网中带有 Spring 启动应用程序。
public 子网中该应用程序服务器前面有一个 Nat 网关。
应用程序使用 Connection: keep-alive header 向远程主机发送请求,远程主机使用相同的 header 发回响应。
所以我可以通过 netstat 看到已建立的连接。
netstat -t | grep <remote server ip>
tcp6 0 0 ip-172-30-4-31.eu:57324 <remote server ip>:http ESTABLISHED
由于 350 秒内没有流量 Nat 网关根据此文档关闭连接:https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-troubleshooting.html#nat-gateway-troubleshooting-timeout
但是连接在应用服务器上还处于Established状态,所以下一个请求到远程服务器给我:
java.net.SocketException: Connection reset
我试图在 sysctl.conf 中的应用程序服务器上进行更改,以几乎同时关闭与 Nat 网关的连接:
net.ipv4.tcp_keepalive_time=351
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=2
但是没有任何反应,通过 tcpdump 从应用程序服务器向远程服务器转储流量没有给我 keep-alive 数据包。
那么除了在我的应用程序中删除连接 header 之外,我还能做些什么来避免这个问题?
问题出在打开套接字的方法上。
我用过 Apache Fluent API:
Request.Post(mainProperties.getPartnerURL())
.addHeader("Signature", SecurityHelper.getSignature(requestBody.getBytes("UTF-8"),
mainProperties.getPartnerKey()))
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.connectTimeout(mainProperties.getRequestTimeoutMillis())
.bodyByteArray(requestBody.getBytes(UTF_8))
.execute().returnContent().asString();
但我已将 so_keepalive 参数设置到套接字。可以使用 HttpClient 来完成:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(true)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(mainProperties.getRequestTimeoutMillis())
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultSocketConfig(socketConfig)
.setDefaultRequestConfig(requestConfig)
.build();
HttpPost post = new HttpPost(mainProperties.getPartnerURL());
post.addHeader("Signature", SecurityHelper.getSignature(requestBody.getBytes("UTF-8"),
mainProperties.getPartnerKey()));
post.addHeader("Content-Type", "text/xml");
post.setEntity(new StringEntity(requestBody, UTF_8));
CloseableHttpResponse response = httpClient.execute(post);
return EntityUtils.toString(response.getEntity(), UTF_8);
然后net.ipv4.tcp_keepalive_time=350设置在我的sysctl.conf(sysctl -p需要申请更改)应用于新连接,可以这样检查:
netstat -o | grep <remote-host>
tcp6 0 0 ip-172-30-4-233.e:50414 <remote-host>:http ESTABLISHED **keepalive (152.12/0/0)**
因此 TCP-Keep-Alive 从最后一个没有响应的数据包开始 350 秒后发送的数据包将关闭 ESTABLISHED 连接。所有 TCP-Keep-Alive 数据包都可以通过 tcp 转储看到:
我有一个 Amazon Linux 2 应用程序服务器,在私有子网中带有 Spring 启动应用程序。 public 子网中该应用程序服务器前面有一个 Nat 网关。 应用程序使用 Connection: keep-alive header 向远程主机发送请求,远程主机使用相同的 header 发回响应。 所以我可以通过 netstat 看到已建立的连接。
netstat -t | grep <remote server ip>
tcp6 0 0 ip-172-30-4-31.eu:57324 <remote server ip>:http ESTABLISHED
由于 350 秒内没有流量 Nat 网关根据此文档关闭连接:https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateway-troubleshooting.html#nat-gateway-troubleshooting-timeout 但是连接在应用服务器上还处于Established状态,所以下一个请求到远程服务器给我:
java.net.SocketException: Connection reset
我试图在 sysctl.conf 中的应用程序服务器上进行更改,以几乎同时关闭与 Nat 网关的连接:
net.ipv4.tcp_keepalive_time=351
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=2
但是没有任何反应,通过 tcpdump 从应用程序服务器向远程服务器转储流量没有给我 keep-alive 数据包。 那么除了在我的应用程序中删除连接 header 之外,我还能做些什么来避免这个问题?
问题出在打开套接字的方法上。 我用过 Apache Fluent API:
Request.Post(mainProperties.getPartnerURL())
.addHeader("Signature", SecurityHelper.getSignature(requestBody.getBytes("UTF-8"),
mainProperties.getPartnerKey()))
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.connectTimeout(mainProperties.getRequestTimeoutMillis())
.bodyByteArray(requestBody.getBytes(UTF_8))
.execute().returnContent().asString();
但我已将 so_keepalive 参数设置到套接字。可以使用 HttpClient 来完成:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(true)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(mainProperties.getRequestTimeoutMillis())
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultSocketConfig(socketConfig)
.setDefaultRequestConfig(requestConfig)
.build();
HttpPost post = new HttpPost(mainProperties.getPartnerURL());
post.addHeader("Signature", SecurityHelper.getSignature(requestBody.getBytes("UTF-8"),
mainProperties.getPartnerKey()));
post.addHeader("Content-Type", "text/xml");
post.setEntity(new StringEntity(requestBody, UTF_8));
CloseableHttpResponse response = httpClient.execute(post);
return EntityUtils.toString(response.getEntity(), UTF_8);
然后net.ipv4.tcp_keepalive_time=350设置在我的sysctl.conf(sysctl -p需要申请更改)应用于新连接,可以这样检查:
netstat -o | grep <remote-host>
tcp6 0 0 ip-172-30-4-233.e:50414 <remote-host>:http ESTABLISHED **keepalive (152.12/0/0)**
因此 TCP-Keep-Alive 从最后一个没有响应的数据包开始 350 秒后发送的数据包将关闭 ESTABLISHED 连接。所有 TCP-Keep-Alive 数据包都可以通过 tcp 转储看到: