一个大量短连接导致FTP连接关闭的案例

2024/12/04

一个大量短连接导致FTP连接关闭的案例

FTP 服务器是一种用于文件传输的网络服务协议,它有两种工作模式:主动模式和被动模式。在主动模式下,FTP服务器主动向客户端发起数据传输的连接,而在被动模式下,FTP 服务器等待客户端发起数据传输的连接。被动模式可以避免一些防火墙或路由器的限制,被动模式会由服务器再开发一个数据传输端口,再由客户端去连接这个数据传输端口上传或下载数据,因此在公网上更常用。与被动模式相反的是主动模式,是由客户端开启一个数据传输端口,由服务端来连接客户端,在防火墙或者是 NAT 存在的情况下,服务端就无法跟客户端建立数据传输通道了。

我们遇到了一个由于向FTP服务器发起了大量短连接导致新建的链接被莫名 close 的问题。业务场景是这样的:一些安全性要求比较高的内网之间的数据传输,必须使用FTP服务器来摆渡数据。一个定时任务每次爬取数据后,会将数据发送到FTP服务器上,但每次发送都会新建一个 FTP 连接,这是导致问题的原因。

我们发现,一旦发送量比较多(比如每分钟发送1000个文件),新建的FTP链接虽然可以连接上FTP服务器,但在传输数据时却莫名其妙被FTP服务器断开了。FTP 服务器没有给出任何错误信息,Java 程序只是抛出了一个 Connection closed by remote host 的异常。使用 netstat 命令发现,系统中存在大量连接FTP服务器的链接处于 TIME_WAIT 状态。正常情况下,一个连接在进入 TIME_WAIT 状态后,要经过 2MSL 才会彻底关闭,这些处于TIME_WAIT状态的链接仍然占用了端口号,由于发送方都是在同一台机器,所以数据连接的 TCP 四元组被耗尽了,导致无法再开启新的链接。

我们查看了FTP服务器的配置文件,发现它使用了被动模式,在新启动一个链接用于传输数据时,会占用一个新的端口号。而默认配置下,vsftpd 的被动模式可使用的端口范围只有 1000 个(从21100到22100)。这就意味着如果在短时间内有超过 1000 个链接请求传输数据,就会出现端口不足的情况。这些处于 TIME_WAIT 状态的链接导致服务器无法再开启新的链接传输数据,从而导致 FTP 控制链接正常,但上传或下载数据时却会被断掉。

为了解决这个问题,我们尝试了以下几种方法:

  1. 调高FTP服务器的端口范围。我们将 vsftpd.conf 文件中的 pasv_min_port 和 pasv_max_port 参数分别修改为20000和30000,增加了可用端口数。这样可以缓解端口不足的问题,但也会增加服务器的资源消耗和管理难度。

  2. 降低 net.ipv4.tcp_max_tw_buckets 这个参数的值。这个参数控制了系统中最多允许存在多少个处于 TIME_WAIT 状态的链接。我们将它从默认值 180000 降低到 5000,使得系统能够更快地回收处于 TIME_WAIT 状态的链接。这样可以减少本地端口号的占用,但也会有安全风险或性能损失。

  3. 修改代码,使用连接池,对连接进行复用。我们修改了定时任务的代码,使得它不再每次发送数据都新建一个 FTP 连接,而是使用一个连接池来管理和复用已有的连接。这样可以避免在短时间内产生大量的连接,也可以提高数据传输的效率。

经过测试,我们发现使用连接池是最好的方式,它既解决了问题,又没有带来其他负面影响。因此我们最终采用了使用连接池的方案,部署到了生产环境中。经过一段时间的观察,我们发现问题已经完全消失了,FTP服务器和客户端都能正常工作,数据传输也没有出现任何异常。

Post Directory