首页 > 解决方案 > 如何调试未关闭的 CLOSE_WAIT 连接的原因?(tcpdump 等)

问题描述

我们在同一台主机上安装了 Java 应用程序和 Nginx 作为反向代理。定期地,我们的CLOSE_WAIT连接挂了很长时间:

$ ss -n4t | head
State      Recv-Q Send-Q  Local Address:Port    Peer Address:Port
CLOSE-WAIT 1      0           127.0.0.1:8180       127.0.0.1:36599
CLOSE-WAIT 1      0           127.0.0.1:8180       127.0.0.1:36467
CLOSE-WAIT 1      0           127.0.0.1:8180       127.0.0.1:36154

而且它们的数量正在增加,然后应用程序就会出现问题。互联网说:

Your server is failing to detect client disconnects, or ignoring them, and not closing the socket.

Nginx 说:

2020/06/28 04:59:15 [error] 65506#0: *31719640 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 55.55.55.55, server: app.mycompany.com, request: "POST /url/url HTTP/1.0", upstream: "http://127.0.0.1:8180/url/url/provider", host: "app.mycompany.com"

好的,tcpdump在正常行为期间显示:

2020-06-08 06:58:23.073139 IP 127.0.0.1.8180 > 127.0.0.1.57786: Flags [P.], seq 1:738, ack 1211, win 1365, options [nop,nop,TS val 2780380992 ecr 2780380974], length 737
2020-06-08 06:58:23.073233 IP 127.0.0.1.8180 > 127.0.0.1.57786: Flags [F.], seq 738, ack 1211, win 1365, options [nop,nop,TS val 2780380992 ecr 2780380992], length 0
2020-06-08 06:58:23.073302 IP 127.0.0.1.57786 > 127.0.0.1.8180: Flags [F.], seq 1211, ack 739, win 353, options [nop,nop,TS val 2780380992 ecr 2780380992], length 0

[F.]从双方表示连接已正确关闭(基于图表)。

接下来,tcpdump在异常行为期间(出生时CLOSE_WAIT)显示:

2020-06-08 06:55:30.282015 IP 127.0.0.1.8180 > 127.0.0.1.57160: Flags [.], ack 1380, win 1365, options [nop,nop,TS val 2780208201 ecr 2780208201], length 0
2020-06-08 06:57:10.279006 IP 127.0.0.1.57160 > 127.0.0.1.8180: Flags [F.], seq 1380, ack 1, win 342, options [nop,nop,TS val 2780308198 ecr 2780208201], length 0
2020-06-08 06:57:10.318432 IP 127.0.0.1.8180 > 127.0.0.1.57160: Flags [.], ack 1381, win 1365, options [nop,nop,TS val 2780308238 ecr 2780308198], length 0

这里我们只看到一个[F.]

我已经阅读了数千篇文章,但仍然无法回答以下问题:

tcpdump[F.]标志实际上是什么意思?文档说:Placeholder, usually used for ACK.,但是第一个初始 FIN(没有 ACK)在哪里,例如:

this one? --> 2020-06-08 06:58:23.073233 IP 127.0.0.1.57786 > 127.0.0.1.8180: Flags [F], seq 738, ack 1211, win 1365, options [nop,nop,TS val 2780380992 ecr 2780380992], length 0
2020-06-08 06:58:23.073233 IP 127.0.0.1.8180 > 127.0.0.1.57786: Flags [F.], seq 738, ack 1211, win 1365, options [nop,nop,TS val 2780380992 ecr 2780380992], length 0

我的问题是,tcpdump将 FIN 和 FIN/ACK 组合成[F.]标志?如果是这样,在正常行为期间,我们会看到以下操作顺序:

  1. 客户端向服务器发送 FIN:omitted by tcpdump
  2. 服务器向客户端发送 FIN/ACK:127.0.0.1.8180 > 127.0.0.1.57786: Flags [F.]
  3. 服务器向客户端发送 FIN:omitted by tcpdump
  4. 客户端向服务器发送 FIN/ACK:127.0.0.1.57786 > 127.0.0.1.8180: Flags [F.]

如果是这样,在异常行为期间,客户端根本不会向我们发送 FIN,因此,我们的服务器不会发送 FIN/ACK,即[F.]. 正确的?

第二个问题是 Nginx。据我了解netstat

CLOSE-WAIT 1      0           127.0.0.1:8180       127.0.0.1:36467

连接是从 localhost 到 localhost。是因为 Nginx 反向代理吗?这就是为什么我看不到真正的客户IP?如果是这样,Java-application 和 Nginx 之间会不会有问题?我之所以问,是因为我想调试/监视 HTTP 流量,包括从 localhost 到 localhost 的请求和响应标头以及消息正文:

tcpdump -A -s 0 'tcp port 8180 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -i lo

因为我们在 Nginx 上有 SSL 终止,我相信我会看到服务器/客户端流内部发生了什么。第三个问题是,它是否正确/是否有更多方法可以清楚地理解我们得到“CLOSE_WAIT”的根本原因?

标签: nginxnetworkingtcpwiresharktcpdump

解决方案


推荐阅读