必要性
- 要想Linux发挥最高的能力,要保证项目达到最好的效果,系统参数和内核调优必不可少。
- 比如在写的WEB项目或者使用Nginx时,当遇到大量请求同时到来,往往会出现报错:Too many open files,这个原因就是Linux文件系统最大可打开文件数为1024,每个TCP连接都是操作socket,会打开文件,毕竟Linux一切皆文件。
- 还有Nginx、HAProxy作为反向代理时,需要将请求转到真实后端服务,那么就需要和后端建立TCP连接,这个时候如果后端只有一个服务,那么可建立的连接数理论上最多只能有65535,因为TCP连接由四元组区分,源IP、目的IP和目的端口都是固定的,只有源端口不固定,而端口数我们都知道最大只有65535。但是当实际测试中可能会发现最多只会有3万个连接,原因就是Linux也限制了可使用的端口范围。
- 当遇到SYN攻击、放大攻击、还有反向代理的服务器出现大量TIME_WAIT状态的连接处理也需要调整参数
- 还有TCP半连接队列大小、keepalive的时间等,也可以通过修改参数提高性能,降低消耗
还有很多问题都可以通过调整参数来解决或者避免,此处不再一一细说。
注: 此处的参数都是我工作中搜集使用的,可能不适合所有情况
系统参数调优
需要编辑/etc/security/limits.conf 文件, 将文件末尾的数据替换成以下内容,重启后生效
1 2 3 4 5 6 7
| * soft nofile 2100000 * hard nofile 2100000 * soft memlock unlimited * hard memlock unlimited root soft nofile 2100000 root hard nofile 2100000 root soft memlock unlimited
|
修改这些数据可以使打开文件数变得更大,在网络上就可以建立更多的TCP连接,也就不会出现Too many open files错误了。
当然也可以通过ulimit -n修改,但是这个修改是临时的,会话终止就无效了。
内核调优
内核参数调优需修改 /etc/sysctl.conf 文件, 然后使用 sysctl -p 命令生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| # 可打开文件数大小 fs.file-max=10485760 # 单进程可打开的文件数 fs.nr_open=10485760 # 一个进程可以拥有的VMA(虚拟内存区域)的数量 vm.max_map_count=262144 # SYN半连接队列长度,syncookies启动则无效 net.ipv4.tcp_max_syn_backlog=262144 # accept队列长度 net.core.somaxconn=32768 # 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目 net.core.netdev_max_backlog=262144 # 接收套接字缓冲区大小的缺省值,单位是字节 net.core.rmem_default=262144 # 发送套接字缓冲区大小的缺省值,单位是字节 net.core.wmem_default=262144 # 接收套接字缓冲区大小的最大值,单位是字节 net.core.rmem_max=4194304 # 发送套接字缓冲区大小的最大值,单位是字节 net.core.wmem_max=4194304 # 关闭ip转发功能不充当路由器 net.ipv4.ip_forward=1 net.ipv4.conf.all.send_redirects=0 net.ipv4.conf.default.send_redirects=0 # 是否允许服务绑定一个本机不存在的IP地址 net.ipv4.ip_nonlocal_bind=1 # 允许系统打开的端口范围 net.ipv4.ip_local_port_range=1024 65535 # 确保无人能修改路由表 net.ipv4.conf.default.accept_redirects=0 net.ipv4.conf.all.accept_redirects=0 net.ipv4.conf.all.secure_redirects=0 net.ipv4.conf.default.secure_redirects=0 # 源地址校验 开启反向路径过滤 net.ipv4.conf.default.rp_filter=1 net.ipv4.conf.all.rp_filter=1 # 开启重用,允许将TIME-WAIT sockets 重新用于新的TCP连接 net.ipv4.tcp_tw_reuse=1 # TIME-WAIT快速回收 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_timestamps=1 # TIME-WAIT数量 net.ipv4.tcp_max_tw_buckets=300000 # 开启SYN洪水攻击保护 net.ipv4.tcp_syncookies=1 # 内核放弃建立连接之前发送SYNACK 包的数量 net.ipv4.tcp_synack_retries=1 # 当keepalive 起用的时候,TCP 发送keepalive 消息的频度 net.ipv4.tcp_keepalive_intvl=30 net.ipv4.tcp_keepalive_time=900 net.ipv4.tcp_keepalive_probes=3 # 保持在FIN-WAIT-2状态的时间 net.ipv4.tcp_fin_timeout=10 # 防止孤儿连接过多,导致系统资源长时间被占用 net.ipv4.tcp_max_orphans=131072 # 接收缓冲区发送缓冲区大小 net.ipv4.tcp_rmem=4096 4096 16777216 net.ipv4.tcp_wmem=4096 4096 16777216 net.ipv4.tcp_mem=786432 3145728 4194304 # 防止icmp风暴 net.ipv4.icmp_echo_ignore_broadcasts=1 # 开启恶意icmp错误消息保护 net.ipv4.icmp_ignore_bogus_error_responses=1
|
注意事项
- 上述一些内核参数修改可能会导致产生异常,可以根据具体业务修改特定参数
- 比如tcp_timestamps和tcp_tw_recycle都设置为1,可能会导致在nat的网络环境访问服务器时会有不定时连接超时的问题。当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,这些客户端的时间戳可能存在差异,从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,也就无法建立TCP连接。
- 比如tcp_tw_reuse开启TIME_WAIT重用,这个状态是主动发起TCP关闭的一端会出现,而且会持续2MSL时间之后才会回到初始状态,MSL值是数据包在网络中的最大生存时间,这段时间内这个端口是不能被重用的。正常来说只会影响客户端,服务端不收影响,但是当服务器充当反向代理,比如Nginx、Haproxy之类的就需要发起TCP连接,如果TIME_WAIT过多就无法建立新的连接,所以这些相关参数要适当调整。
- 还有TCP的keepalive,这个和我们通常了解的HTTP keepalive不是一回事,他是TCP的保活机制,如果两端的TCP连接一直没有数据交互,达到了触发TCP保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文,而Linux默认的保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制,还会经过多次探测才会关闭,所以可以修改此参数避免TCP连接占用资源。
小结
参数调优需谨慎,一不注意有可能会导致一些意想不到的问题,但是要想高并发,这些调优还是有必要的。网络方面的学习很重要,特别是TCP相关的知识更需要深入研究一下,之后再去调参数和项目开发则会事半功倍。