常用的Linux内核参数及优化场景
在Linux中,
sysctl
命令被用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录/proc/sys
中。需要注意的是,sysctl命令对内核参数的修改,在系统重启后会丢失,如果希望参数持久化,可以直接修改配置文件/etc/sysctl.conf
下面根据工作中遇到的内核参数调优,阐述一些常用于调优的内核参数及其使用场景。
网络层面
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文件命名格式。