通常来看,Redis开发和运维人员更加关注的是Redis本身的一些配置优化,例如AOF和RDB的配置优化、数据结构的配置优化等,但是对于操作系统是否需要针对Redis做一些配置优化不甚了解或者不太关心。然而事实证明一个良好的系统操作配置能够为Redis服务良好运行保驾护航。
1.内存分配控制
1.vm.overcommit_memory
Redis在启动时可能会出现这样的日志:
# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add ‘vm.overcommit_memory = 1‘ to /etc/sysctl.conf and then reboot or run the command ‘ sysctl vm.overcornmit_memory=1‘ for this to take effect.
在分析这个问题之前,首先要弄清楚什么是overcommit? Linux操作系统对大部分申请内存的请求都回复yes,以便能运行更多的程序。因为申请内存后,并不会马上使用内存,这种技术叫做overcommit。如果Redis在启动时有上面的日志,说明vm.overcommit_memory=0,Redis 提示把它设置为 1。
vm.overcommit_memory用来设置内存分配策略,有三个可选值,如表12-1所示。
表 12-1 vm.overcommit_memory 的三个可选值及说明 |
|
值 |
含 义 |
0 |
表示内核将检査是否有足够的可用内存。如果有足够的可用内存,内存申请通过,否则内存申请失败,并把错误返回给应用进程 |
1 |
表示内核允许超量使用内存直到用完为止 |
2 |
表示内核决不过量的("never overcommit") 使用内存,即系统整个内存地址空间不能超过swap+50%的RAM值,50%是overcommit ratio 默认值,此参数同样支持修改 |
日志中的Background save代表的是bgsave和bgrewriteaof,如果当前可用内存不足,操作系统应该如何处理fork 操作。如果vm.overcommit_memory=0,代表如果没有可用内存,就申请内存失败,对应到Redis就是执行fork 失败,在Redis的日志会出现:
Cannot allocate memory
Redis建议把这个值设置为1,是为了让fork操作能够在低内存下也执行成功。
2.获取合适置
获取:
# cat /proc/sys/vm/overcommit_memory 0
设置:
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf sysctl vm.overcommit_memory=1
3.最佳实践
□ Redis设置合理的maxmemory,保证机器有20% ~ 30%的闲置内存。
□ 集中化管理AOF 重写和RDB的bgsave。
□ 设置vm.overcommit_memory=1, 防止极端情况下会造成fork失败。
2.swappiness
1.参数说明
swap对于操作系统来比较重要,当物理内存不足时,可以将一部分内存页进行swap操作,已解燃眉之急。但世界上没有免费午餐,swap空间由硬盘提供,对于需要高并发、高吞吐的应用来说,磁盘IO通常会成为系统瓶颈。在 Linux中,并不是要等到所有物理内存都使用完才会使用到swap,系统参数swppiness会决定操作系统使用swap的倾向程度。swappiness的取值范围是0 ~ 100, swappiness的值越大,说明操作系统可能使用swap的概率越高,swappiness值越低,表示操作系统更加倾向于使用物理内存。swap的默认值是60, 了解这个值的含义后,有利于Redis的性能优化。表12-2对 swappiness的重要值进行了说明。
表 12-2 swapniess 重要值策略说明 |
|
值 |
策略 |
0 |
Linux3.5 以及以上: 宁愿用OOM killer 也不用swap Linux3.4 以及更早: 宁愿用 swap也不用OOM killer |
1 |
Linux3.5 以及以上:宁愿用swap也不用OOM killer |
60 |
默认值 |
100 |
操作系统会主动地使用 swap |
从表12-2中可以看出,swappiness参数在Linux3.5版本前后的表现并不完全相同,Redis运维人员在设置这个值需要关注当前操作系统的内核版本。
2.设置方法
swappiness设置方法如下:
echo {bestvalue} > /proc/sys/vm/swappiness
但是上述方法在系统重启后就会失效,为了让配置在重启Linux操作系统后立即生效,只需要在 /etc/sysctl.conf 追加 vm.swappiness={bestvalue} 即可。
echo vm.swappiness={bestvalue} >> /etc/sysctl.conf
需要注意 /proc/sys/vm/swappiness是设置操作,/etc/sysctl.conf是追加操作。
3.THP
Redis在启动时可能会看到如下日志:
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command ‘ echo never > /sys/kernel/mm/transparent_hugepage/enabled‘ as root, and add it to your / etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
从提示看Redis建议修改Transparent Huge Pages (THP) 的相关配置,Linux kernel在2.6.38内核增加了THP特性,支持大内存页(2MB) 分配,默认开启。当开启时可以降低fork 子进程的速度,但 fork 操作之后,每个内存页从原来4KB变为2MB, 会大幅增加重写期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询,例如简单的 incr 命令也会出现在慢查询中。因此Redis日志中建议将此特性进行禁用,禁用方法如下:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
为了使机器重启后THP配置依然生效,可以在/etc/rc.local中追加 echo never >/sys/kernel/mm/transparent_hugepage/enabled 。
在设置THP配置时需要注意:有些Linux的发行版本没有将THP放到 /sys/kernel/mm/transparent_hugepage/enabled中,例如 Red Hat 6 以上的 THP 配置放到/sys/kernel/mm/redhat—transparent_hugepage/enabled中。而Redis 源码中检查 THP时,把 THP位置写死:
FILE *fp = fopen ("/sys/kernel/mm/transparent_hugepage/enabled"," r " ) ; if (!fp) return 0;
所以在发行版中,虽然没有THP的日志提示,但是依然存在THP所带来的问题:
echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled
4.OOM killer
OOM killer会在可用内存不足时选择性地杀掉用户进程,它的运行规则是怎样的,会选择哪些用户进程“下手”呢? OOM killer 进程会为每个用户进程设置一个权值,这个权值越高,被“下手”的概率就越高,反之概率越低。每个进程的权值存放在/proc/{progress—id }/oom_score 中,这个值是受/proc/{progress_id}/oom_adj 的控制,oom_adj在不同的 Linux 版本中最小值不同,可以参考 Linux 源码中oom.h (从-15到-17)。当oom_adj设置为最小值时,该进程将不会被OOM killer杀掉,设置方法如下。
echo {value} > /proc/${process_id}/oom_adj
对于Redis所在的服务器来说,可以将所有Redis的oom_adj设置为最低值或者稍小的值,降低被ooM killer 杀掉的概率:
for redis_pid in $ (pgrep -f " redis-server" ) do echo -17 > /proc/${ redis_pid}/oom_adj done
5.ulimit
如果设置比较低,就会出现一下提示。这里不多做解释。
# You requested maxclients of 10000 requiring at least 10032 max file descriptors . # Redis can‘t set maximum open files to 10032 because of OS error: Operation not permitted. # Current maximum open files is 4096. Maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase ‘ulimit - n‘ .
日志解释如下:
□ 第一行:Redis建议把open files至少设置成10032,那么这个10032是如何来的呢?因为maxclients默认是10000,这些是用来处理客户端连接的,除此之外,Redis内部会使用最多32个文件描述符,所以这里的10032 = 10000 + 32。
□ 第二行:Redis不能将open files设置成10032,因为它没有权限设置。
□ 第三行:当前系统的open files是 4096,所以将max clients设置成4096-32=4064个,如果你想设置更高的maxclien ts, 请使用ulimit -n 来设置。从上面的三行日志分析可以看出open files的限制优先级比maxclients大。
6.TCP backlog
Redis默认的tcp-backlog值为511,可以通过修改配置tcp-backlog进行调整,如果 Linux的tcp-backlog小于Redis设置的tcp-backlog,那么在Redis启动时会看到如下日志:
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/ net/core/somaxconn‘ is set to the lower value of 128
查看方法:
# cat /proc/sys/net/core/somaxconn 128
修改方法:
echo 511 > /proc/sys/net/core/somaxconn
7.总结
Linux相关优化:
- vm.overcommit_memory 建议为 1。
- Linux>3.5, vm.swappiness 建议为 1 , 否则建议为 0。
- Transparent Huge Pages(THP)建议关闭掉,但需要注意 Linux 发行版本改变了THP的配置位置。
- 可以为Redis进程设置oom_adj,减少Redis被 ppM killer杀掉的概率,但不要过度依赖此特性。
- 建议对Redis所有节点所在机器使用NTP服务。
- 设置合理的ulimit保证网络连接正常。
- 设置合理的tcp-backlog参数。