我有一台 SLES 机器,它会在 CLOSE_WAIT 状态下累积 TCP 连接,似乎永远不会发生。这些描述符最终会耗尽所有可用内存。目前,我已经有 3037 个,但在最近匆忙重启之前这个数字要高得多。
有趣的是,它们不是来自与我期望有侦听进程的本地端口的连接。它们没有关联的 PID,并且它们的计时器似乎已过期。
# netstat -ton | grep CLOSE_WAIT
tcp 176 0 10.0.0.60:54882 10.0.0.12:31663 CLOSE_WAIT off (0.00/0/0)
tcp 54 0 10.0.0.60:60957 10.0.0.12:4503 CLOSE_WAIT off (0.00/0/0)
tcp 89 0 10.0.0.60:50959 10.0.0.12:3518 CLOSE_WAIT off (0.00/0/0)
# netstat -tonp | grep CLOSE_WAIT
tcp 89 0 10.0.0.59:45598 10.0.0.12:1998 CLOSE_WAIT -
tcp 15 0 10.0.0.59:60861 10.0.0.12:1938 CLOSE_WAIT -
tcp 5 0 10.0.0.59:56173 10.0.0.12:1700 CLOSE_WAIT -
当涉及到 TCP 堆栈或内核网络时,我不是黑带,但 TCP 配置似乎很正常,因为根据手册页,这些值是默认值:
# cat /proc/sys/net/ipv4/tcp_fin_timeout
60
# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
那么什么给出呢?如果计时器过期了,堆栈不应该自动清除这些东西吗?随着这些事情的积累,我实际上给了自己一个长期的拒绝服务。
答案1
不,没有超时CLOSE_WAIT
。我认为这就是off
你的输出的含义。
要退出CLOSE_WAIT
,应用程序必须显式关闭套接字(或退出)。
如果在进程栏中netstat
显示:-
- 您是否以适当的权限和功能运行(例如作为 root)?
- 它们可能是内核进程(例如 nfsd)
答案2
CLOSE_WAIT
表示客户端正在关闭连接,但应用程序尚未关闭它,或者客户端尚未关闭。您应该确定哪个或哪些程序存在此问题。尝试使用
netstat -tonp 2>&1 | grep CLOSE
确定哪些程序保持连接。
如果没有列出任何程序,则该服务由内核提供。这些可能是 RPC 服务,例如nfs
或rpc.lockd
。可以列出侦听内核服务
netstat -lntp 2>&1 | grep -- -
除非 RPC 服务已绑定到固定端口,否则它们将绑定到您的连接显示的临时端口。您可能还想检查其他服务器上的进程和安装。
您可以通过执行以下操作将 NFS 服务绑定到固定端口:
- 选择四个未使用的 NFS 端口(此处使用 32763-32766)
- 添加 NFS 的固定端口
/etc/services
rpc.statd-bc 32763/udp # RCP statd 广播 rpc.statd-bc 32763/tcp rpc.statd 32764/udp # RCP statd 监听 rpc.statd 32764/tcp rpc.mountd 32765/udp # RPC挂载 rpc.mountd 32765/tcp rpc.lockd 32766/udp # RPC lockd/nlockmgr rpc.lockd 32766/tcp
- 配置 statd 以使用选项
--port 32763 --outgoing-port 32764
- 配置 rpcmountd 以使用该选项
--port 32765
- 关闭并重新启动 NFS 和 RPC 服务。
答案3
虽然米克尔的回答可能也是正确的,像 NFS 这样的内核端套接字可能会导致这种情况,CLOSE_WAIT -
没有关联 FD 的条目更常见:
listen()
之前在本地队列中时被对方关闭的连接accept()
可以被调用,请参阅我的详细答案与重现在这里。
处于 CLOSE_WAIT 状态,似乎是永远的
他们将永远保持这种状态,直到你
accept()
他们然后是close()
他们,或者close()
整个套接字(这可能不是一个解决方案)。
这在本文中也有详细解释链接答案。
这些描述符最终会耗尽所有可用内存。
这不应该发生,因为根据man 2 listen
,队列的长度listen()
受到限制
/proc/sys/net/ipv4/tcp_max_syn_backlog # default 4096
/proc/sys/net/core/somaxconn # default 4096
当然,除非您有多个套接字listen()
,因为上述限制是针对每个此类套接字的。