CentOS( 5 )- 内核参数优化

一、文件句柄数限制

Linux系统对单用户单个进程可打开的文件数量有限制,每一个TCP连接都需要创建一个Socket句柄,每个Socket句柄同时也是一个文件句柄,这个设置会直接影响到系统可支撑的最大连接数。

默认单个进程最大可打开1024个文件,通过ulimit -n可以查看打开的最大文件数限制:

$ ulimit -n
1024

限制分为软限制和硬限制,ulimit -n显示的是软限制的数量,用户可以设置自己的限制数量,但受限于最大硬限制设置的值。

[peng@peng-master-1 ~]$ ulimit -SHn 1000
[peng@peng-master-1 ~]$ ulimit -SHn 10000
-bash: ulimit: open files: 无法修改 limit 值: 不允许的操作

注:ulimit命令只影响当前Shell环境

如果要永久生效,可以通过调整文件/etc/security/limits.conf

$ cat /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536

其中类型的值可以为hardsoft或者-,其中-相当于同时配置了hardsoft两行。

软限制(soft nofile)是指Linux在当前系统能够承受的范围内进一步限制用户同时打开的文件数;硬限制(hard nofile)则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。通常软限制小于或等于硬限制。

修改后重新登录即可生效。同时系统层面也有可打开的文件数量限制,根据系统的资源情况计算出来的。

系统层面限制

查看与临时修改系统打开文件总数限制:

$ cat /proc/sys/fs/file-max
95079
$ echo 1620826 > /proc/sys/fs/file-max

永久修改系统打开文件最大值限制:

$ sysctl -a | grep file-max
fs.file-max = 1620826

$ vi /etc/sysctl.conf
fs.file-max = 1000000

# 立即生效:
$ sysctl -p

查看进程资源限制与打开的文件

$ cat /proc/2309/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            10485760             unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             63691                63691                processes
Max open files            1024                 4096                 files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       63691                63691                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

$ lsof -p 2309
COMMAND    PID   USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
zabbix_se 2309 zabbix  cwd    DIR              252,1     4096       2 /
zabbix_se 2309 zabbix  rtd    DIR              252,1     4096       2 /
zabbix_se 2309 zabbix  txt    REG              252,1  3506157 1050689 /usr/local/zabbix/sbin/zabbix_server
zabbix_se 2309 zabbix  mem    REG              252,1   803410  267760 /lib64/ld-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1 10114254  269365 /lib64/libc-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1   858324  269378 /lib64/libpthread-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1   102750  269377 /lib64/libdl-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1  2452986  269371 /lib64/libm-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1    91096  269369 /lib64/libz.so.1.2.3
zabbix_se 2309 zabbix  mem    REG              252,1   172659  269388 /lib64/librt-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1   340018  269509 /lib64/libresolv-2.18.so
zabbix_se 2309 zabbix  mem    REG              252,1   528075  269246 /lib64/libnsl-2.18.so

二、内核参数优化

/etc/sysctl.conf配置内核参数,修改之后生效需执行:sysctl -p

2.1 TCP参数优化

(图一:Three-Way Handshake)

(图二:Four-Way Wavehand)

net.ipv4.tcp_syncookies

net下的参数也可以在/proc/sys/net/下看到对应的文件。

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 65535

对于一个TCP连接,ServerClient需要通过三次握手来建立网络连接.当三次握手成功后,我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了。

对于服务器而言,一个完整的连接建立过程,服务器会经历 2 种 TCP 状态:SYN_REVD, ESTABELLISHED。对应也会维护两个队列:

  1. 一个存放SYN的队列(半连接队列)
  2. 一个存放已经完成连接的队列(全连接队列)

当一个连接的状态是SYN RECEIVED时,它会被放在SYN队列中。当它的状态变为ESTABLISHED时,它会被转移到另一个队列。所以后端的应用程序只从已完成的连接的队列中获取请求。如果一个服务器要处理大量网络连接,且并发性比较高,那么这两个队列长度就非常重要了。因为,即使服务器的硬件配置非常高,服务器端程序性能很好,但是这两个队列非常小,那么经常会出现客户端连接不上的现象,因为这两个队列一旦满了后,很容易丢包,或者连接被复位。所以,如果服务器并发访问量非常高,那么这两个队列的设置就非常重要了。

net.ipv4.tcp_max_syn_backlog:是指定所能接受SYN同步包的最大客户端数量,即半连接上限,默认值是128,即SYN_REVD状态的连接数。

net.core.somaxconn:是Linux中的一个kernel参数,指的是服务端所能accept即处理数据的最大客户端数量,即完成连接上限,默认值是128.

如果客户端发出SYNC包后不回应ACK包,则可能造成半连接队列满。客户端可以用此发起SYN FLOOD攻击。而SYN Cookie技术可以让服务器在收到客户端的SYN报文时,不分配资源保存客户端信息,而是将这些信息保存在SYN+ACK的初始序号和时间戳中。对正常的连接,这些信息会随着ACK报文被带回来。上面配置开启了net.ipv4.tcp_syncookies参数。另外也可以配置:

net.ipv4.tcp_tw_recycle

查看当前系统的TCP连接情况,可以看到TIME_WAIT的数量比较多。在主动关闭的一方发出最后的ACK后状态变为TIME_WAIT,但这个时候会等待2MSL的时间,如果这个时间内没有收到被动关闭方的重传的FIN包,则结束TCP连接,主要是为了防止最后的ACK包发送后对方没有收到而重传FIN包。

但过多的TIME_WAIT会占用掉一部分端口,TCP/IP协议中端口号的范围是0-65535,也就是只有65536端口,而下面示例就占用了接近2万个。

$ netstat -tn | awk '$1=="tcp"{print $NF}' | sort | uniq -c | sort -nr
  19622 TIME_WAIT
    166 ESTABLISHED
     12 SYN_SENT
      9 LAST_ACK
      8 FIN_WAIT2
      3 CLOSING

这个接近2w的数值是怎么来的?sysctl.conf中看到配置:

net.ipv4.tcp_max_tw_buckets = 20000

这个参数表示系统保持TIME_WAIT的最大值,默认为180000。设为较小数值此项参数可以控制TIME_WAIT套接字的最大数量,避免服务器被大量的TIME_WAIT套接字拖死。

网上看到的优化TIME_WAIT方案基本是开启net.ipv4.tcp_tw_recycle,用于TIME_WAIT的快速回收。这个开关需要和net.ipv4.tcp_timestamps配合使用(默认开启),如:

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 1

但貌似这个参数打开后问题比较多,所以目前线上系统并未开启这个配置。

TIME_WAIT对应的是COSE_WAIT,被动关闭方收到关闭请求后置为CLOSE_WAIT状态,但没有在主动发包,通常是程序里对资源没有调用Close Socket操作。

net.ipv4.tcp_tw_reuse

net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1

开启TCP连接重用,允许将TIME_WAIT的连接用于新的TCP连接,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout

net.ipv4.tcp_fin_timeout = 30

设置FIN-WAIT-2超时时间,当主动关闭的一方处于该状态,但一直收不到对方的FIN包时,超过设定的时间就直接CLOSE掉了。

net.ipv4.tcp_keepalive_time

net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_intvl = 2
net.ipv4.tcp_keepalive_probes = 2

默认是2个小时。tcp_keepalive_intvl表示探测包发送的时间间隔,默认75s。tcp_keepalive_probes对方不予应答发送探测包的次数,默认是9次。

net.ipv4.ip_local_reserved_ports

net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.ip_local_reserved_ports = 9001,30001

有时候重启服务的时候发现某个端口被占用导致服务无法启动,可以设置此参数,TCP建立连接时从ip_local_port_range中选取端口,同时会排除ip_local_reserved_ports中设定的端口。

2.2 系统丢包

当请求量到一定数量时可能会出现丢包的情况,这个时候就可能跟nf_conntrack模块的设置有关了。通过系统日志可以看到类似kernel: nf_conntrack: table full, dropping packet的日志信息。nf_conntrack模块会使用一个哈希表记录TCP协议“established connection”记录,当这个哈希表满之后,新的连接会引发“nf_conntrack: table full, dropping packet”错误。

net.netfilter.nf_conntrack_max

sudo sysctl -w net.netfilter.nf_conntrack_max=1503232
sudo sysctl -w net.netfilter.nf_conntrack_buckets=375808  # 如果使用非4.19内核,该选项可能无法在运行时修改
sudo sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=60

2.3 Swap分区

vm.swappiness = 0

内核参数vm.swappiness控制换出运行时内存的相对权重,参数值大小对如何使用swap分区有很大联系。值越大,表示越积极使用swap分区,越小表示越积极使用物理内存。默认值swappiness=60,表示内存使用率超过100-60=40%时开始使用交换分区。

swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间;swappiness=100的时候表示积极使用swap分区,并把内存上的数据及时搬运到swap空间。

(网上有的说,对于3.5以后的内核和RedHat 2.6.32之后的内核,设置为0会禁止使用swap,从而引发out of memory,这种情况可以设置为1。)

如果需要,可打开,然后设置Swap分区

dd if=/dev/zero of=/mnt/swap bs=block_size count=number_of_block
注:block_size、number_of_block 大小可以自定义,比如bs=1M count=1024 代表设置1G大小swap分区

$ dd if=/dev/zero of=/data/swap bs=10M count=2048
记录了2048+0 的读入
记录了2048+0 的写出
21474836480字节(21 GB)已复制,13.5878 秒,1.6 GB/秒

$ mkswap /mnt/swap
$ swapon /mnt/swap
$ echo "/mnt/swap swap swap defaults 0 0" >> /etc/fstab
$ free -m
             total       used       free     shared    buffers     cached
Mem:        127162      63028      64133          1        142      51670
-/+ buffers/cache:      11215     115946
Swap:        20479          0      20479

2.4 内存分配策略

vm.overcommit_memory = 1

它是 内存分配策略,可选值:0、1、2。

完整示例

vm.swappiness = 0
kernel.sysrq=1

net.ipv4.neigh.default.gc_stale_time = 120

# see details in https://help.aliyun.com/knowledge_detail/39428.html
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2

# see details in https://help.aliyun.com/knowledge_detail/41334.html
net.ipv4.tcp_max_tw_buckets = 20000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200

net.core.somaxconn = 65535
net.netfilter.nf_conntrack_max = 1503232
#net.netfilter.nf_conntrack_buckets = 375808
net.netfilter.nf_conntrack_tcp_timeout_established = 1200

Redis开启bgsave可考虑设置vm.overcommit_memory = 1


-- EOF --
最后更新于: 2024-08-17 14:44
发表于: 2017-12-24 19:30
标签: 运维 CentOS