Skip to content

Linux kernel parameters optimization

homepage-banner

Linux内核文件系统

/proc 文件系统中,可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。这些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却显示为0字节,因为这些都是驻留在内存中的文件。

  • /proc/sys/net 是跟网络相关的内核参数。
  • /proc/sys/kernel 是跟内核相关的内核参数。
  • /proc/sys/vm 是跟内存相关的内核参数。
  • /proc/sys/fs 是跟文件系统相关的内核参数。

查看内核参数

1、要查看 /proc/sys/ 目录中某个内核参数文件,可以使用 cat 命令查看内容

cat /proc/sys/net/ipv4/ip_forward

2、也可以使用 sysctl 来查看

sysctl net.ipv4.ip_forward

临时修改内核参数

1、使用 echo 修改

echo 1 > /proc/sys/net/ipv4/ip_forward

2、使用 sysctl -w 修改

sysctl -w net.ipv4.ip_forward=1

永久修改内核参数

为了让修改在重启后不失效,可以在 /etc/sysctl.conf 文件中添加

net.ipv4.ip_forward=1

然后执行

sysctl -p

系统kernel参数优化

/proc/sys/kernel/panic

这个参数用来设置如果发生内核严重错误(Kernel panic),则内核在重新引导之前等待的时间(以s为单位)。默认值为0,表示在发生内核严重错误时将禁止重新引导,建议设置为1,也就是内核故障后1s自动重启。

echo 1 > /proc/sys/kernel/panic

/proc/sys/kernel/pid_max

参数用来设置Linux下进程数量的最大值。默认值是32768,正常情况下是够用的,当任务重时,会不够用,最终导致内存无法分配的错误。

echo 196608 > /proc/sys/kernel/pid_max

/proc/sys/kernel/ctrl-alt-del

该值控制系统在接收到〈Ctrl+Alt+Delete〉组合键时如何反应。

  • 0值,表示捕获 〈Ctrl+Alt+Delete〉,并将其送至init程序。这将允许系统可以安全地关闭和重启,就好像输入shutdown命令一样。
  • 1值,表示不捕获 〈Ctrl+Alt+Delete〉

/proc/sys/kernel/core_pattern

用来设置 core 文件保存位置或文件名,只有文件名时,则保存在应用程序运行的目录下

echo "core.%e.%p" > /proc/sys/kernel/core_pattern

其中,%e 表示程序名,%p 表示进程id。

内存内核参数优化

/proc/sys/vm/dirty_background_ratio

参数指定了当文件系统缓存脏数据数量达到系统内存百分之多少时(如10%)就会触发pdflush/flush/kdmflush等后台回写进程运行,将一定缓存的脏页异步地刷入磁盘。例如,服务器内存 32G,那么有 3.2G 的内存可以用来缓存脏数据,超过3.2G,pdflush/flush/kdmflush进程就会来清理。

/proc/sys/vm/dirty_ratio

参数指定了当文件系统缓存脏数据数量达到系统内存百分之多少时(如 15%),系统不得不开始处理缓存脏页(因为此时脏数据数量已经比较多,为了避免数据丢失需要将一定脏数据刷入磁盘)。如果触发了这个设置,那么新的 I/O 请求将会被阻挡,直到脏数据被写进磁盘。这是造成I/O卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制。

注意这个参数和 dirty_background_ratio 参数的区别,dirty_background_ratio 是脏数据百分比的一个软限制,而 dirty_ratio 是脏数据百分比的一个硬限制,在参数设置上, dirty_ratio 一定要大于或等于 dirty_background_ratio 的值。

/proc/sys/vm/dirty_expire_centisecs

参数表示如果脏数据在内存中驻留时间超过该值, pdflush进程在下一次将把这些数据写回磁盘。这个参数声明Linux内核写缓冲区里面的数据多”旧”了之后,pdflush 进程就开始考虑写到磁盘中去。单位是(1/100)s。默认值是3000,也就是30s的数据就算旧了,将会刷新磁盘。对于特别重载的写操作来说,这个值可以适当缩小,但也不能缩小太多,因为缩小太多也会导致I/O提高太快。

/proc/sys/vm/dirty_writeback_centisecs

参数控制内核的脏数据刷新进程pdflush的运行间隔。单位是(1/100)s。默认值是500,也就是5s。如果系统是持续地写入动作,那么建议降低这个数值,这样可以把尖峰的写操作削平成多次写操作;相反,如果系统是短期地尖峰式的写操作,并且写入数据不大且内存又比较富裕,那么应该增大此数值。

/proc/sys/vm/vfs_cache_pressure

参数表示内核回收用于directory和inode cache内存的倾向。默认值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比。降低该值低于 100,将导致内核倾向于保留 directory 和 inodecache;增加该值超过100,将导致内核倾向于回收directory和inodecache。此参数一般情况下不需要调整,只有在极端场景下才建议进行调整。

/proc/sys/vm/min_free_kbytes

参数表示强制Linux VM最低保留多少空闲内存(Kbytes)。默认值为90112(88M物理内存,CentOS7版本),保持默认即可。

/proc/sys/vm/nr_pdflush_threads

参数表示当前正在运行的pdflush进程数量,在I/O负载高的情况下,内核会自动增加更多的pdflush进程。

/proc/sys/vm/overcommit_memory

参数指定了内核针对内存分配的策略,其值可以是0、1、2。其中,0 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。1表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2表示内核允许分配超过所有物理内存和交换空间总和的内存。

/proc/sys/vm/panic_on_oom

参数表示内存不够时内核是否直接panic(恐慌)。默认值为0,表示当内存耗尽时,内核会触发OOMkiller杀掉最耗内存的进程。如果设置为1表示在OOM时系统会panic(恐慌)。Linux Kernel panic正如其名,表示Linux Kernel不知道如何运行,此时它会尽可能把此时能获取的全部信息都打印出来。有时候为了不让系统自动kill掉进程,需要设置此值为1。

/proc/sys/vm/swappiness

参数表示使用Swap分区的概率。swappiness=0 时表示最大限度使用物理内存,然后才是 Swap 空间;swappiness=100 时表示积极使用 Swap 分区,并且把内存上的数据及时搬运到Swap空间里面。Linux默认设置为60,表示物理内存在使用到40%(100-60)的时候,就开始使用交换分区。

文件系统内核参数优化

/proc/sys/fs/file-max

参数指定了可以分配的文件句柄的最大数目。如果用户得到的错误消息声明由于打开文件数已经达到了最大值而不能打开更多文件,则可能需要增加该值。

/proc/sys/fs/inotify/max_user_watches

Linux下 rsync+inotify-tools 实现数据实时同步中有一个重要的配置就是设置inotify的 max_user_watches 值,如果不设置,当遇到大量文件的时候就会出现出错的情况。

网络内核参数优化

/proc/sys/net/ipv4/tcp_syn_retries

参数表示对于一个新建连接,内核要发送多少个SYN连接请求才决定放弃。此值不应该大于255,默认值是5,建议设置为2。

/proc/sys/net/ipv4/tcp_keepalive_time

参数表示当 keepalive 启用的时候,TCP 发送 keepalive 消息的频度。默认值是7200s,建议修改为300s。

/proc/sys/net/ipv4/tcp_orphan_retries

参数表示孤儿 Socket 废弃前重试的次数,重负载Web服务器建议调小。

/proc/sys/net/ipv4/tcp_syncookies

参数表示开启SYN Cookies。当出现SYN等待队列溢出时,启用 Cookies 来处理,可防范少量 SYN 攻击。默认值为 0,表示关闭,普通 Web服务器建议设置为1。

这里提到了 SYN 攻击,它是当前最流行的 DoS(拒绝服务)与 DDoS(分布式拒绝服务)的方式之一。它利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接第1个握手包(SYN包)。被攻击服务器回应第2个握手包(SYN+ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第3个握手包。导致被攻击服务器保持大量 SYN_RECV 状态的”半连接”,并且会默认重试5次回应第2个握手包,直到塞满TCP等待连接队列,资源耗尽(CPU满负荷或内存不足),让正常的业务请求连接不进来。

针对 SYN 攻击,可以启用 SYN Cookie 、设置 SYN 队列最大长度以及设置 SYN+ACK 最大重试次数。设置 tcp_syncookies 为1就是启用了 SYN Cookie

SYN Cookie 的作用是缓解服务器资源压力。启用之前,服务器在接到 SYN 数据包后,会立即分配存储空间,并随机化一个数字作为 SYN 号发送 SYN+ACK 数据包。然后保存连接的状态信息等待客户端确认。而在启用 SYN Cookie 之后,服务器不再马上分配存储空间,而且通过基于时间种子的随机数算法设置一个 SYN 号,替代完全随机的 SYN 号。发送完 SYN+ACK 确认报文之后,清空资源不保存任何状态信息。直到服务器接到客户端的最终 ACK 包。同时,通过 Cookie 检验算法鉴定是否与发出去的 SYN+ACK 报文序列号匹配,匹配则通过完成握手,失败则丢弃。

/proc/sys/net/ipv4/tcp_max_syn_backlog

参数表示设置 SYN队列最大长度,默认值为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。tcp_max_syn_backlog 是使用服务器的内存资源换取更大的等待队列长度,让攻击数据包不至于占满所有连接而导致正常用户无法完成握手。所以会消耗系统部分内存资源。

/proc/sys/net/ipv4/tcp_synack_retries

该参数用来降低服务器SYN+ACK 报文重试次数(默认是5次),尽快释放等待资源。对于远端的连接请求SYN,内核会发送SYN+ACK数据报文,以确认收到上一个SYN连接请求包。这是所谓的三次握手(threeway handshake)机制的第2个步骤。此参数是决定内核在放弃连接之前所送出的SYN+ACK的数目。

上面这三个参数与 SYN 攻击的危害一一对应,完完全全是对症下药。但这些措施也是双刃剑,设置过大可能消耗服务器更多的内存资源,甚至影响正常用户建立TCP连接,因此,需要评估服务器硬件资源和攻击力度谨慎设置。

/proc/sys/net/ipv4/tcp_tw_recycle

参数表示开启TCP连接中TIME-WAIT sockets的快速回收,默认值为0,表示关闭,普通Web服务器建议设置为1。

这里重点介绍一下 TIME-WAIT。这个 TIME_WAIT 是指在TCP四次挥手过程中,首先调用关闭连接发起的一方,在发送最后一个ACK之后就会进入 TIME_WAIT 的状态,过多的 TIME_WAIT 连接,有什么坏处呢?

在高并发短连接的 TCP 服务器上,当服务器处理完请求后,会立刻主动正常关闭连接,此时就会出现大量 Socket 处于 TIME_WAIT 状态。如果客户端的并发量持续增高,此时部分客户端就会显示连接不上服务器,因为服务器端资源用完了。这里的资源主要指服务器临时连接端口。

服务器可用的端口是0~65535,其实这真的很少,再刨除系统和其他服务要用的,剩下的就更少了。而高并发短连接场景可以让服务器在短时间范围内同时占用大量端口。

例如,访问一个Web页面1s的HTTP短连接处理完成,在关闭连接之后,这个业务用过的端口会停留在 TIME_WAIT 状态几分钟,而这几分钟,其他HTTP请求过来时是无法占用此端口的。如果此时监控服务器的利用率会发现,服务器干正经事的时间和端口(资源)被挂着,无法被使用的时间比例是1比几百,这就导致服务器资源严重浪费。

所以对于 Web 服务器进行优化时,要特别注意这个 TCP 状态 TIME_WAIT,要查看系统的 TIME_WAIT 状态,可以使用如下命令组合:

netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn

通过开启 TIME-WAIT sockets 的快速回收,可以在很大程度上减轻Web服务器的负担,所以Web服务器中关于 TIME-WAIT 的优化是必须要做的。

Linux 从 4.12 内核版本开始移除了 tcp_tw_recycle 配置。

/proc/sys/net/ipv4/tcp_tw_reuse

参数表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,因为重用连接,比重新建立新连接要方便得多。此值默认值为0,表示关闭。

/proc/sys/net/ipv4/tcp_fin_timeout

参数表示处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。建议设置为15。

/proc/sys/net/ipv4/tcp_keepalive_probes

参数用来减少超时前的探测次数,普通Web服务器建议设置为5。

/proc/sys/net/core/netdev_max_backlog

参数用来设置每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。默认值为 1000。修改此参数可以优化网络设备接收队列,建议设置为3000。

/proc/sys/net/core/rmem_max、wmem_max

两个参数可以提高TCP的最大缓冲区大小。

  • rmem_max :表示接收套接字缓冲区大小的最大值(以字节为单位)。
  • wmem_max :表示发送套接字缓冲区大小的最大值(以字节为单位)。

作为网络参数的基础优化,建议设置为:

echo 16777216 > /proc/sys/net/core/rmem_max
echo 16777216 > /proc/sys/net/core/wmem_max

/proc/sys/net/ipv4/tcp_rmem、tcp_wmem

两个参数可以提高Linux 内核自动对 Socket缓冲区进行优化的能力。

  • tcp_rmem :用来配置读缓冲的大小,第1个值为最小值,第2个值为默认值,第3个值为最大值。
  • tcp_wmem :用来配置写缓冲的大小,第1个值为最小值,第2个值为默认值,第3个值为最大值。

作为网络参数的基础优化,建议设置为:

echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 65536 16777216" > /proc/sys/net/ipv4/tcp_wmem

/proc/sys/net/core/somaxconn

参数用来设置 Socket 监听(listen)的 backlog 上限。什么是 backlog 呢? backlog 就是 Socket 的监听队列,当一个请求(request)尚未被处理或建立时,它会进入 backlog。而 Socket server 可以一次性处理 backlog 中的所有请求,处理后的请求不再位于监听队列中。当Server处理请求较慢,以至于监听队列被填满后,新来的请求会被拒绝。默认值为128。作为网络参数的基础优化,建议设置为4096。

最佳实践

线上环境建议将所有要设置的内核参数加入到 /etc/sysctl.conf 文件中。

net.nf_conntrack_max = 2097152
## net.ipv4.tcp_tw_reuse = 1
## net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_tw_buckets = 80000
net.ipv4.tcp_max_tw_buckets = 500000
net.ipv4.tcp_max_syn_backlog = 20000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_fin_timeout = 10
net.ipv4.ip_local_port_range = 1024  65535
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.core.wmem_max = 16777216
net.core.wmem_default = 8388608
net.core.somaxconn = 32768
net.core.rmem_max = 16777216
net.core.rmem_default = 8388608
net.core.netdev_max_backlog = 32768
Leave a message