我在运行自己的爬网程序时遇到了一个奇怪的套接字问题。由于协议设计,它可以快速打开和关闭大量 TCP 套接字。这是我必须忍受的事情。我非常确定在代码中我已经正确关闭了套接字(通过strace
和调试打印进行验证)。但不知何故,我仍然达到了系统的开放套接字限制。 Netdat 等工具也显示打开套接字的数量有所增加。经进一步检查。我发现里面有大量的套接字文件描述符/proc/<pid>/fd/
。这是我运行的示例结果
所有命令都执行为root
# ls /proc/248298/fd/ -l | grep socket | wc -l
522
但是,当我运行netstat
以找出套接字连接到哪个远程时,同时考虑系统范围的 TIME_WAIT 和 CLOSE_WAIT 套接字(因为 netstat 不再将它们与我的进程关联)。这个数字要低得多。
# netstat -tulnap | egrep '(TIME_WAIT|CLOSE_WAIT|248298)' | wc -l
109
我尝试将其设置net.ipv4.tcp_tw_reuse
为1
缓解措施,但没有成功。
这是什么原因呢?更进一步,为什么我关闭的套接字仍然被认为是活动的?或者有办法解决这个问题吗?
操作系统:Linux
发行版:Ubuntu 22.04
内核:5.15
CPU:x64
答案1
这称为短暂端口压力,可能会影响高流量系统,这些系统会与各种其他服务建立大量连接,其中包括不太合法的网络流量。操作系统为此保留的端口各不相同,RFC 关于端口范围的建议也各不相同(比较 RFC 6056、RFC 6335)。
在 Linux 上最简单的旋钮是net.ipv4.ip_local_port_range
,对于进行大量连接的系统,可能应该将其设置得尽可能大:
sysctl -w net.ipv4.ip_local_port_range=1024\ 65535
这可能会导致使用 1024 到 65535 范围内的端口的其他网络服务出现问题(可能是 NFS 的 RPC?)。或者,为了测试其他方法的有效性,可以故意将该值设置得较小,以使有问题的状态更容易重现:
sysctl -w net.ipv4.ip_local_port_range=30000\ 30100
这么低的范围当然可能会破坏随机服务。建议使用测试虚拟机或提供对测试系统的控制台访问。
否则,有各种旋钮可以减少连接在各种状态下花费的时间长度(您没有
FIN_WAIT*
在问题中列出任何可能导致计数关闭的状态),但如果设置得太低,这些可能会增加风险各种问题,例如出现延迟或重复的数据包时。如果远程系统由于速率限制而丢弃数据包,则这种情况不太可能发生。