修改网络内核对TCP连接的有关限制

尽管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接。

原因一: 本地端口号范围有限制

问题出在connect()调用返回失败,查看系统错误提示消息是 “Can’t assign requestedaddress”。同时,如果在此时用 tcpdump 工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在于本地Linux系统内核中有限制。其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由于每个TCP客户端连接都要占用一个唯一的本地端,内核限制本地端口号的范围为1024~32768之中),如果现有的TCP客户端连接已将所有的本地端口号占满,则此时就无法为新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can’t assignrequested address”。有关这些控制逻辑可以查看Linux内核源代码,以linux2.6内核为例,可以查看tcp_ipv4.c文件中如下函数:

	static int tcp_v4_hash_connect(struct sock *sk)

请注意上述函数中对变量 sysctl_local_port_range 的访问控制。变量 sysctl_local_port_range 的初始化则是在 tcp.c 文件中的如下函数中设置:

	void __init tcp_init(void)

解决方案:

    vim /etc/sysctl.conf
	net.ipv4.ip_local_port_range = 1024 65000 # 端口范围的最大值则应小于或等于65535,理论上单独一个进程最多可以同时建立60000多个TCP客户端连接
    sysctl -p

原因二:Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。

此时程序会表现为在 connect()调用中阻塞,如同死机,如果用 tcpdump 工具监视网络,也会发现根本没有 TCP 连接时客户端发 SYN 包的网络流量。
由于 IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位于内核内存中的conntrackdatabase中,
这个数据库的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法为新的TCP连接建立跟踪信息,于是表现为在connect()调用中阻塞。
此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:

    vim /etc/sysctl.conf
	net.ipv4.ip_conntrack_max = 10240 # 系统对最大跟踪的TCP连接数限制设置为10240,此限制值要尽量小,以节省对内核内存的占用。理论上单独一个进程最多可以同时建立10000多个TCP客户端连接
    $ sysctl -p