TCP——连接核心参数
一、SO_SEND_BUF和SO_REC_BUFF
- SO_SEND_BUF是操作系统内核的写缓冲区,所有应用程序需要发送到对端的信息,都会放到该缓冲区中,等待发往对端
- SO_REC_BUFF是操作系统内核的读缓冲区,所有对端发过来的数据都会放到该缓冲区中,等待应用程序取走
linux下socket缓冲区大小的默认值分别在以下两个文件中:
发送缓冲区:
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
接收缓冲区:
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4194304
注:第一个表示最小值,第二个表示默认值,第三个表示最大值
二、文件数限制
- 1、临时修改方式(不需要关闭远程连接)
ulimit -n 65536
- 2、永久修改方式(需要关闭远程连接)
修改/etc/security/limits.conf文件,在文件中添加如下行:
* soft nofile 65536 * hard nofile 65536 * soft nproc 131072 * hard nproc 131072
其中:
- xxx指定了要修改哪个用户的打开文件数限制,可用"*"号表示修改所有用户的限制;
- soft或hard指定要修改软限制还是硬限制;
- 65535则指定了想要修改的新的限制值,请注意软限制值要小于或等于硬限制。
- nofile表示最大句柄数,也可理解为一台服务器建立socket连接的最大数,2.6.25内核之前默认限制是1024*1024。
- nproc表示最大进程数。
- 3、修改/etc/pam.d/login文件【可省略】
在文件中添加如下行:
session required /lib/security/pam_limits.so
这是告诉Linux在用户完成系统登录后,应该调用pam_limits.so模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制),
而pam_limits.so模块就会从/etc/security/limits.conf文件中读取配置来设置这些限制值。修改完后保存此文件。
- 4、查看Linux系统级的最大打开文件数限制【可省略】
使用如下命令:
[root@localhost yum.repos.d]# cat /proc/sys/fs/file-max 387412
这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)387412个文件,是Linux系统级硬限制,所有用户级的打开文件数限制都不应超过这个数值。
通常这个系统级硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不应该修改此限制,除非想为用户级打开文件数限制设置超过此限制的值。
修改此硬限制的方法是修改/etc/rc.local脚本,在脚本中添加如下行:
echo 487412 > /proc/sys/fs/file-max
这是让Linux在启动完成后强行将系统级打开文件数硬限制设置为487412。修改完后保存此文件。
- 5、完成上述步骤后重启系统
重启命令:
shutdown -r now
三、修改网络内核对TCP连接的有关限制
- 无法成功建立新的TCP连接的现象原因
在Linux上编写支持高并发TCP连接的客户端通讯处理程序时,有时会发现尽管已经解除了系统对用户同时打开文件数的限制,
但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接的现象。出现这种现象的原因有多种。最可能是因为Linux网络内核对本地端口号范围有限制。
此时,进一步分析为什么无法建立TCP连接,会发现问题出在connect()调用返回失败,查看系统错误提示消息是“Can’t assign requestedaddress”。
同时,如果在此时用tcpdump工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在于本地Linux系统内核中有限制。
其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如,内核限制本地端口号的范围为1024~32768之间)。
当系统中某一时刻同时存在太多的TCP客户端连接时,由于每个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),
如果现有的TCP客户端连接已将所有的本地端口号占满,则此时就无法为新的TCP客户端连接分配一个本地端口号了,
因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can’t assignrequested address”。
- 有关TCP连接的参数
net.ipv4.ip_local_port_range = 32768 61000 表示用于向外连接的端口范围。缺省情况下过窄:32768到61000,改为1024到65535。 net.ipv4.tcp_keepalive_time = 7200 (/proc/sys/net/ipv4/tcp_keepalive_time) 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,建议改为30分钟(1800)。 net.ipv4.tcp_keepalive_probes = 9 (/proc/sys/net/ipv4/tcp_keepalive_probes) 表示当keepalive起用的时候,TCP发送keepalive探测以确定该连接已经断开的次数,默认值是9次。 net.ipv4.tcp_keepalive_intvl = 75 (/proc/sys/net/ipv4/tcp_keepalive_intvl) 表示当keepalive起用的时候,探测消息发送的频率(在认定连接失效之前,发送多少个TCP的keepalive探测包),默认值是75秒。 net.ipv4.tcp_tw_timeout = 60 表示TCP状态中TIME_WAIT的过期时间,默认情况是60秒。 net.ipv4.tcp_tw_reuse = 0 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭。 net.ipv4.tcp_tw_recycle = 0 表示开启TCP连接中TIME-WAIT sockets的快速回收,NAT环境可能导致DROP掉SYN包。默认为0,表示关闭。 Linux 从4.12内核版本开始移除了 tcp_tw_recycle 配置
net.ipv4.tcp_max_tw_buckets = 180000
表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,可适当增大该值,但不建议减小。
net.ipv4.tcp_timestamps = 1 表示TCP连接不再检查请求数据包的时间戳,默认为1,表示开启。 net.ipv4.tcp_max_syn_backlog = 1024 (/proc/sys/net/ipv4/tcp_max_syn_backlog) 表示半连接队列(syn queue)的长度,TCP第一次握手,会将请求放入syn queue,默认为1024,加大队列长度可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_syncookies = 0
表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭。
net.core.somaxconn = 262144 (cat /proc/sys/net/core/somaxconn)
表示系统同时发起的TCP连接数,一般默认值为128。
表示全连接队列(accept queue)的长度,TCP第三次握手,会将请求从syn queue转移到accent queue中。
net.ipv4.tcp_synack_retries = 5
在TCP三次握手中,服务端向客户端发送第二次握手包(SYN+ACK包)后,如果服务端收不到第三次握手包(ACK包)时服务端进行的重试次数,默认值是5次,每次等待30~40秒,即“半连接”默认hold住大约180秒。
如果设置为0,则不进行重试,【作用】:加快回收“半连接”,不要耗光资源;【副作用】:网络状况很差时,如果对方没收到第二个握手包,可能连接服务器失败;
net.ipv4.tcp_syn_retries = 5
在TCP三次握手中,客户端向服务端发送第一次握手包(SYN)后,如果客户端收不到第二次握手包(SYN+ACK包)时客户端进行的重试次数,默认值是5次,每次等待30~40秒,即“半连接”默认hold住大约180秒。
net.core.rmem_max = 16777216
表示socket最大的读(数据接收)缓存,单位是byte。
net.core.wmem_max = 16777216 表示socket最大的写(数据发送)缓存,单位是byte。
net.ipv4.tcp_fin_timeout = 30
表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。
net.ipv4.nf_conntrack_max = 102400
表示防火墙最大跟踪的TCP连接数。请注意,此限制值要尽量小,以节省对内核内存的占用。
net.ipv4.tcp_rmem = 4096 87380 16777216
表示为每个TCP连接分配的读缓冲区内存大小,单位是byte。
第一个数字表示,为TCP连接分配的最小内存,
第二个数字表示,为TCP连接分配的缺省内存,
第三个数字表示,为TCP连接分配的最大内存(net.core.rmem_max可覆盖该值)
net.ipv4.tcp_wmem = 4096 65536 16777216 表示为每个TCP连接分配的写缓冲区内存大小,单位是byte。 第一个数字表示,为TCP连接分配的最小内存, 第二个数字表示,为TCP连接分配的缺省内存, 第三个数字表示,为TCP连接分配的最大内存(net.core.wmem_max可覆盖该值) net.ipv4.tcp_window_scaling = 0 表示启用支持更大的TCP窗口。如果TCP窗口最大超过65535(64KB),必须设置该数值为1。 net.ipv4.tcp_sack = 1 表示启用转发应答,可以进行有选择应答(SACK)从而减少拥塞情况的发生。 net.core.netdev_max_backlog = 262144 表示当每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许发送到队列的数据包的最大数目,默认是1000。对重负载服务器而言,该值太低,可调整到262144。 net.ipv4.tcp_no_metrics_save = 1 表示一个tcp连接关闭后,把这个连接曾经有的参数,比如慢启动门限snd_sthresh、拥塞窗口snd_cwnd、srtt等信息保存到dst_entry中, 只要dst_entry没有失效,下次新建立相同连接的时候就可以使用保存的参数来初始化这个连接。通常情况下是关闭的。 net.ipv4.tcp_max_orphans = 262144 用于设定系统中最多允许存在多少tcp套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,没有与用户文件句柄关联的tcp套接字符将立即被复位,同时给出警告信息。这个限制只是为了防止简单的DoS工具。一般在系统内存比较充足的情况下,可以增大这个参数的赋值。
四、重点说明
1. net.ipv4.tcp_tw_reuse
将处于TIME_WAIT状态的socket用于新的TCP连接,影响连出的连接。默认是关闭状态,即等于0。
需要打开对TCP时间戳的支持,即net.ipv4.tcp_timestamps=1(默认即为1)。
使用限制:
- 只适用于客户端(连接发起方)
- TIME_WAIT创建时间超过1秒才可以被复用
2. net.ipv4.tcp_tw_recycle
启用TIME_WAIT 状态的sockets的快速回收,影响所有连入和连出的连接。默认是关闭状态,即等于0。
需要打开对TCP时间戳的支持,即net.ipv4.tcp_timestamps=1(默认即为1)。
使用问题:
Linux会丢弃所有来自远端的timestramp时间戳小于上次记录的时间戳(由同一个远端发送的)的任何数据包。也就是说要使用该选项,则必须保证数据包的时间戳是单调递增的。
问题在于,此处的时间戳并不是我们通常意义上面的绝对时间,而是一个相对时间。很多情况下,我们是没法保证时间戳单调递增的,比如使用了nat,lvs等情况。
而这也是很多优化文章中并没有提及的一点,大部分文章都是简单的推荐将net.ipv4.tcp_tw_recycle设置为1,却忽略了该选项的局限性,最终造成严重的后果。
引用: