高并发编程-1 Linux系统调优
2022-08-18 00:00:00

必要性

  • 要想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

注意事项

  1. 上述一些内核参数修改可能会导致产生异常,可以根据具体业务修改特定参数
  2. 比如tcp_timestamps和tcp_tw_recycle都设置为1,可能会导致在nat的网络环境访问服务器时会有不定时连接超时的问题。当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,这些客户端的时间戳可能存在差异,从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,也就无法建立TCP连接。
  3. 比如tcp_tw_reuse开启TIME_WAIT重用,这个状态是主动发起TCP关闭的一端会出现,而且会持续2MSL时间之后才会回到初始状态,MSL值是数据包在网络中的最大生存时间,这段时间内这个端口是不能被重用的。正常来说只会影响客户端,服务端不收影响,但是当服务器充当反向代理,比如Nginx、Haproxy之类的就需要发起TCP连接,如果TIME_WAIT过多就无法建立新的连接,所以这些相关参数要适当调整。
  4. 还有TCP的keepalive,这个和我们通常了解的HTTP keepalive不是一回事,他是TCP的保活机制,如果两端的TCP连接一直没有数据交互,达到了触发TCP保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文,而Linux默认的保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制,还会经过多次探测才会关闭,所以可以修改此参数避免TCP连接占用资源。

小结

参数调优需谨慎,一不注意有可能会导致一些意想不到的问题,但是要想高并发,这些调优还是有必要的。网络方面的学习很重要,特别是TCP相关的知识更需要深入研究一下,之后再去调参数和项目开发则会事半功倍。