每次写日志,都要先搜索一番,开头怎么写。要装出很牛B的样子,让自己有优越感。这次QTMD的吧,技术人说话简单直接。之前在workman的群里看到一小哥,聊什么优化内核参数。我就想所谓内核参数优化,指什么呢?
所谓内核参数优化:linux系统中针对业务服务应用而进行的系统内核参数调整。
优化并无一定的标准。
1 最大文件数
我们常听说linux万物皆文件,一个连接要打开一个socket句柄文件。那么打开的文件句柄数(文件描述符),就一定程序上限制着我们的连接数。
1> 用户级限制 : 目标用户运行的所有进程总共能打开的文件描述符数
ulimit -n 默认是1024 这表示当前用户的每个进程最多允许同时打开1024个文件。
这1024个文件中还得除去每个进程必然打开的标准输入,
标准输出,标准错误,服务器监听 socket,进程间通讯的unix域socket等文件,
那么剩下的可用于客户端socket连接的文件数就只有大概1024-10=1014个左右。
也就是说缺省情况下,基于Linux的通讯程序最多
允许同时1014个TCP并发连接)
临时修改 :max-file-number
ulimit -SHn max-file-number
永久修改方法:
sudo vim /etc/security/limits.conf
添加如下两行
* hard nofile max-file-number # 系统硬限制
* soft nofile max-file-number # 软限制
2> 系统级限制: 所有用户总共能打开的文件描述符数
查看最大 cat /proc/sys/fs/file-max
临时修改 sysctl -w fs.file-max=max-file-number
永久修改 在 /etc/sysctl.conf fs.file-max=max-file-number
注意:以上需要执行sysctl -p 使更改生效
单个进程 打开的文件数
fs.nr_open
NR_OPEN是一个进程可以打开的最大文件数
查看方法:
cat /proc/sys/fs/nr_open 1048576
sysctl -a | grep fs.nr_open
修改方法:
sysctl -w fs.nr_open = 1048576
2 TCP连接数量
查看linux内核版本:uname -r。
半连接的数量:
tcp_max_syn_backlog 该参数决定了系统中处于 SYN_RECV 状态的 TCP 连接数量。SYN_RECV 状态指的是当系统收到 SYN 后,作了 SYN+ACK 响应后等待对方回复三次握手阶段中的最后一个 ACK 的阶段。
查看方法:
cat /proc/sys/net/ipv4/tcp_max_syn_backlog 256
sysctl -a |grep net.ipv4.tcp_max_syn_backlog
修改方法:
sysctl -w net.ipv4.tcp_max_syn_backlog = 511
该参数定义了系统中每一个端口最大的监听队列的长度,是个全局参数。该参数和 net.ipv4.tcp_max_syn_backlog 有关联,后者指的是还在三次握手的半连接的上限,该参数指的是处于 ESTABLISHED 的数量上限。若您的业务负载很高,则有必要调高该参数。listen(2) 函数中的参数 backlog 同样是指明监听的端口处于 ESTABLISHED 的数量上限,当 backlog 大于 net.core.somaxconn时,以 net.core.somaxconn 参数为准。
超过这个数量就会看到connection refused。
查看方法:
cat /proc/sys/net/core/somaxconn 128
修改方法:
sysctl -w net.core.somaxconn = 511
上图可以看出来,somaxconn和tcp_max_syn_backlog 会选择两个当中比较小的那个来作为全连接的队列的长度。
这俩数值适当的调整(QPS=backlog),如果backlog过小(较小值),在大量并发连接的情况下,容易造成Accept_queue 溢出。 这个值php的fpm默认的是511 (listen.backlog = 511) ,nginx 也是默认511。
2 tcp缓冲区参数
tcp发送缓冲区
cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
它包含3个值,分别指定一个socket的TCP写缓冲区的最小值,默认值和最大值。
可参考的优化值: 8192 436600 873200
发送缓冲区大小,理想数值是吞吐量 * 延迟,这样才可以达到最大网络利用率。
tcp接收缓冲区
/proc/sys/net/ipv4/tcp_rmem 它包含3个值,分别指定一个socket 的tcp读缓冲区的最小值,默认值 最大值 通过修改这个参数 可以改变接收 通告窗口的大小
tcp内存大小
注意这里单位是页:一页=4kb=4096字节
cat /proc/sys/net/ipv4/tcp_mem
23604 31474 47208
low press high
low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。
pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。
high:允许所有tcp sockets用于排队缓冲数据报的页面量,当内存占用超过此值,系统拒绝分配socket,后台日志输出“TCP: too many of orphaned sockets”。(dmesg 可以看到)
tcp_syncookies
/proc/sys/net/ipv4/tcp_syncookies 指定是否打开TCP同步标签(syncookie),同步标签通过启动cookie来 自同一个地址的连接请求,而导致listen 监听队列溢出。
该参数表示是否打开 TCP 同步标签(SYN_COOKIES),内核必须开启并编译 CONFIG_SYN_COOKIES,SYN_COOKIES 可以防止一个套接字在有过多试图连接到达时引起过载。默认值 0 表示关闭。
当该参数被设置为 1 且 SYN_RECV 队列满了之后,内核会对 SYN 包的回复做一定的修改,即,在响应的 SYN+ACK 包中,初始的序列号是由源 IP + Port、目的 IP + Port 及时间这五个参数共同计算出一个值组成精心组装的 TCP 包。由于 ACK 包中确认的序列号并不是之前计算出的值,恶意攻击者无法响应或误判,而请求者会根据收到的 SYN+ACK 包做正确的响应。启用 net.ipv4.tcp_syncookies 后,会忽略 net.ipv4.tcp_max_syn_backlog。
tcp重试次数
cat /proc/sys/net/ipv4/tcp_syn_retries 5 次 该参数指明了处于 SYN_RECV 状态时重传 SYN+ACK 包的次数。 (每次超时重试时间为 2^n-1 秒)默认为5 减少重复次数,可以快速释放半连接。 修改为1或者2.
关闭 TCP 连接时,TCP 连接的两端都可以发起关闭连接的请求,若对端发起了关闭连接,但本地没有关闭连接,那么该连接就会处于 CLOSE_WAIT 状态。虽然该连接已经处于半开状态,但是已经无法和对端通信,需要及时的释放掉该链接
开启端口复用 这样,被 TIME_WAIT 状态占用的端口,还能用到新建的连接中。
net.ipv4.tcp_tw_reuse
查看方式:
sysctl -a |grep tcp_tw_reuse 默认是 0
修改方式
sysctl -w net.ipv4.tcp_tw_reuse = 1
增大处于TIME_WAIT 状态的连接数量
可以调整内核中管理 TIME_WAIT 状态的数量,当实例中处于 TIME_WAIT 及需要转换为 TIME_WAIT 状态连接数之和超过了 net.ipv4.tcp_max_tw_buckets 参数值时,message 日志将报错
message 日志中将报错 time wait bucket table,同时内核关闭超出参数值的部分 TCP 连接。您需要根据实际情况适当调高 net.ipv4.tcp_max_tw_buckets,同时从业务层面去改进 TCP 连接。
执行 netstat -ant|grep TIME_WAIT|wc -l 统计处于 TIME_WAIT 状态的 TCP 连接数
net.ipv4.tcp_max_tw_buckets :增大处于TIME_WAIT 状态的连接数量
sysctl -a |grep tcp_max_tw_buckets 查看方式,默认值是 4096
建议修改值:
sysctl -w net.ipv4.tcp_max_tw_buckets = 1048576
缩短处于FIN_WAIT_2 状态的时长。
HTTP 服务中,Server 由于某种原因会主动关闭连接,例如 KEEPALIVE 超时的情况下。作为主动关闭连接的 Server 就会进入 FIN_WAIT2 状态
TCP/IP 协议栈中,存在 半连接 的概念,FIN_WAIT2 状态不算做超时,如果 Client 不关闭,FIN_WAIT_2 状态将保持到系统重启,越来越多的 FIN_WAIT_2 状态会致使内核 Crash。
减少这个数值以便加快系统关闭处于 FIN_WAIT2 状态的 TCP 连接。
/proc/sys/net/ipv4/tcp_fin_timeout 默认60 建议设置30
配套配置的话
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
出现大量 CLOSE_WAIT 状态的 TCP 连接
关闭 TCP 连接时,TCP 连接的两端都可以发起关闭连接的请求,若对端发起了关闭连接,但本地没有关闭连接,那么该连接就会处于 CLOSE_WAIT 状态。虽然该连接已经处于半开状态,但是已经无法和对端通信,需要及时的释放掉该链接.
建议从业务层面及时判断某个连接是否已经被对端关闭,即在程序逻辑中对连接及时关闭检查。
解决思路
编程语言中对应的读、写函数一般包含了检测 CLOSE_WAIT TCP 连接功能,例如:
Java 语言:
通过 read 方法来判断 I/O 。当 read 方法返回 -1 时则表示已经到达末尾。
通过 close 方法关闭该链接。
C 语言:
检查 read 的返回值:
若等于 0 则可以关闭该连接。
若小于 0 则查看 errno,若不是 AGAIN 则同样可以关闭连接。
端口范围
cat /proc/sys/net/ipv4/ip_local_port_range
32768 61000
表示TCP/UDP协议允许使用的本地端口号
因此新连接的本地端口将介于32768和61000之间,默认情况下28232个随机端口,看起来很多,但在繁忙的流量服务器的时候可能很容易达到这个限制。
增大本地端口范围,可以支持更多连接,提高整体的并发能力
增大本地端口的范围
sysctl -w net.ipv4.ip_local_port_range = "1024 65535"
KEEPALIVE
减少 Keepalive 探测失败后,一直到通知应用程序前的重试次数
net.ipv4.tcp_keepalive_probes。
查看方法 sysctl -a |grep net.ipv4.tcp_keepalive_.*
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9 //在这个连接被认为是断开之前,keep alive请求被重发的次数
sysctl -w net.ipv4.tcp_keepalive_probes=3;//建议修改值:3
net.ipv4.tcp_keepalive_time = 7200 // KeepAlive的空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2小时) 这个值在nginx配置中 keepalive_timeout 65;
默认65s
建议修改值:
net.ipv4.tcp_keepalive_intvl = 75 //:探测消息发送的频率,每75s发送一次。建议值 30
修改方法
sysctl -w net.ipv4.tcp_keepalive_intvl=30 //KeepAlive探测包的发送间隔,默认值为75s
net.ipv4.tcp_keepalive_time = 7200 //tcp 发送keepalive的消息频率 建议值600
sysctl -w net.ipv4.tcp_keepalive_time=600
意思是如果某个TCP连接在idle 2个小时后,内核才发起probe.如果probe 9次(每次75秒)不成功,内核才彻底放弃,认为该连接已失效.对服务器而言,显然上述值太大。
网络层优化
ip_conntrack 是 Linux 系统内 NAT 的一个跟踪连接条目的模块。ip_conntrack 模块会使用一个哈希表记录 TCP 协议 established connection 记录,当这个哈希表满了的时候,便会导致 nf_conntrack: table full, dropping packet 错误,会出现网络连接丢包的问题。Linux 系统会开辟一个空间用来维护每一个 TCP 链接,这个空间的大小与 nf_conntrack_buckets、nf_conntrack_max 相关,后者的默认值是前者的 4 倍,而前者在系统启动后无法修改,所以一般都是建议调大 nf_conntrack_max
增大连接跟踪表的大小
net.netfilter.nf_conntrack_max 1048576
sysctl -w net.netfilter.nf_conntrack_max=1048576
修改超时参数:net.netfilter.nf_conntrack_tcp_timeout_established = 1200 默认为432000秒
1 开启ip转发
net.ipv4.ip_forward = 1
2 增大数据包的生存周期
sysctl -a |grep net.ipv4.ip_default_ttl 默认值是64,这个其实会降低系统性能
3 开启数据包的反向地址校验,防止IP欺骗,减少伪造IP带来的DDOS问题
net.ipv4.conf.eth0.rp_filter = 1
调整MTU
从分片角度出发,最主要的是调整MTU(maximum transmission unit)的大小
通常,MTU 的大小应该根据以太网的标准来设置。以太网标准规定,一个网络帧最大为 1518B,那么去掉以太网头部的 18B 后,剩余的 1500 就是以太网 MTU 的大小。
查看:cat /sys/class/net/eth0/mtu 默认是 1500
修改: echo "1450" > /sys/class/net/eth0/mtu
禁止 ICMP 协议
可以禁止 ICMP 协议,即设置 net.ipv4.icmp_echo_ignore_all = 1。这样,外部主机就无法通过 ICMP 来探测主机。
设置为1之后,再来ping会显示超时的。
或者,你还可以禁止广播 ICMP,即设置 net.ipv4.icmp_echo_ignore_broadcasts = 1。
可以避免 ICMP 主机探测、ICMP Flood 等各种网络问题
net.core.netdev_max_backlog
当内核处理速度比网卡接收速度慢时,这部分多出来的包就会被保存在网卡的接收队列上,而该参数说明了这个队列的数量上限。这个数值默认是1000.