Contents

常用的Linux内核参数及优化场景

在Linux中,sysctl命令被用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录/proc/sys中。需要注意的是,sysctl命令对内核参数的修改,在系统重启后会丢失,如果希望参数持久化,可以直接修改配置文件/etc/sysctl.conf

下面根据工作中遇到的内核参数调优,阐述一些常用于调优的内核参数及其使用场景。

/img/golang-cpu-cache/linux-kernel.jpg

网络层面

net.core.somaxconn

net.core.somaxconn表示Socket的监听队列(backlog)长度上限,当一个请求尚未被处理或者建立时,它就会进入监听队列。Socket Server会从backlog中获取请求进行处理,处理后的请求不再位于backlog中,当Server处理较慢时、或者并发请求较多时,backlog被填满后,传入的新请求就会被直接拒绝。

目前在Redis容器化中,我们在Redis容器中设置net.core.somaxconn = 2048,因为Redis的tcp-backlog参数必须小于该内核参数,我们要预留足够的热配置空间。

net.ipv4.tcp_max_tw_buckets

设置处于TIME_WAIT状态的连接数最大值。服务端繁忙会导致TIME_WAIT大量增多,可以将此参数调小用来节省资源。

该参数默认值一般为32768,对于Web服务器或代理服务器,如Nginx,建议设置为6000。

net.ipv4.tcp_tw_recycle

设置为1,快速回收TIME_WAIT状态的连接。

net.ipv4.tcp_tw_reuse

设置为1,表示复用TIME_WAIT的连接,即TIME_WAIT状态的连接重新用于新的TCP连接

net.ipv4.tcp_syncookies

设置为1表示开启,服务端接收客户端的SYNC后,在向客户端发送SYNC+ACK之前,会要求客户端在短时间内回应一个序列号,如果客户端无回应或序列号有误则认为客户端不合法。这样可以避免Sync Flood攻击。

Sync FLood攻击的原理就是在TCP三次握手的开始阶段,客户端向服务端发送SYNC请求后直接关闭,不接收服务端发起的SYNC+ACK,会导致服务端多次尝试重发,大量这种半连接会导致服务端资源被严重消耗。加入序列号判断,避免了服务端的大量重试。

net.ipv4.tcp_max_syn_backlog

设置系统能接受的最大半连接状态的TCP连接数。客户端向服务端发送了SYNC包,服务端收到后会记录,该参数决定最多能记录几个这样的连接。

在受到Sync Flood攻击时,异常半连接会激增,导致正常业务连接无法访问,对外体现为服务端故障,受到Sync Flood攻击时可以视情况调大该参数。

net.netfilter

TODO

存储层面

vm.overcommit_memory

Memory overcommit的含义是操作系统承诺给进程的内存大小超过了实际可用的内存。比如某个进程malloc()了200MB内存,但实际上只用到了100MB,按照UNIX/Linux的算法,物理内存页的分配发生在使用的瞬间,而不是在申请的瞬间,也就是说如果不允许overcommit,未用到的100MB内存根本就没有分配,这100MB内存就闲置了。

commit(或overcommit)针对的是内存申请,内存申请不等于内存分配,内存只在实际用到的时候才分配。

vm.overcommit_memory接受三种取值:

  • 0:表示内核将检查是否有足够的可用内存供应用进程使用(使用一定的算法);如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
  • 1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
  • 2:当系统分配的内存超过swap+N%物理RAM时,会拒绝commit。 其中(N%由vm.overcommit_ratio这一内核参数决定)

设置vm.overcommit_memory = 1是Redis常见的内核参数优化。Redis在执行BGSAVE生成RDB时,会fork出一个子进程,与父进程占用相同的内存。如果vm.overcommit_memory设置为0,会导致子进程申请内存失败,无法执行。该参数也会体现在Redis的日志Warning中。

/sys/kernel/mm/transparent_hugepage/enabled

内核启用了透明大页,可能导致出现Redis延迟升高和异常内存使用的现象,这个也会体现在Redis的日志Warning中。可以使用如下命令关闭透明大页:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

关于透明大页对Redis性能影响的具体原理,可以参考我的这篇文章中的对应部分:Redis大规模应用最佳实践#关闭透明大页

vm.swappiness

该参数定义内核使用swap的积极程度,对应文件/proc/sys/vm/swappiness,默认值是60,可以的取值范围是0-100。

不同的取值情况举例:

  • 0: 仅在物理内存不足的情况下,一般是当剩余空闲内存低于vm.min_free_kbytes limit时,使用交换空间(基本上等同于禁止Swap)
  • 1: 内核版本3.5及以上、Red Hat内核版本2.6.32-303及以上,进行最少量的交换,而不禁用交换。
  • 10:对于一般的应用,当系统存在足够内存时,推荐设置为该值以中和性能和稳定性。
  • 100: 内核将积极的使用交换空间。

对于Redis是需要禁用Swap的,否则在内存水位高时,会出现严重的性能问题。

其他

ulimit -c unlimited

ulimit 是 shell 的内置命令。在执行ulimit命令时,其实是 shell 自身调用。默认情况下,Linux在程序异常时不产生core文件,要想让程序异常退出时产生core dump文件,需要使用ulimit命令更改coredump的设置:表示在程序异常时产生core dump文件,并且不对core dump文件的大小进行限制。

ulimit -c unlimited 

ulimit -n 65535

指定同一时间最多可开启的文件数。如果一个进程已经启动,再去这样调整ulimit是无效的,可以考虑修改/proc/{pid}/limits来实现动态修改。

kernel.core_uses_pid

在程序不寻常退出时,内核会生成一个core文件(是一个内存映像,同时加上调试信息)。使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数。

kernel.core_uses_pid默认为0,表示生成的core文件统一命名为core;设置为1,表示添加 pid作为扩展名,生成的core文件格式为core_xxx。可以配合/proc/sys/kernel/core/core_pattern 修改core文件命名格式。

参考

  1. sysctl命令 – 配置内核参数
  2. 理解Linux的Memory Overcommit
  3. Linux使用笔记: 定制core dump文件的文件名
  4. Linux Netfilter 调优
  5. 连接跟踪(conntrack):原理、应用及 Linux 内核实现