线上计数系统遇到一个奇怪的问题,进程在做备份时,系统内存迅速变小,25G内存被吃掉,最后进程大量占用swap,导致服务响应缓慢,SLA下降严重。
最后发现跟Transparent hugepage相关,具体记录如下。
1 计数系统备份说明
cache系统占用内存在10-100G级别,备份是在每日凌晨低峰时间进行,备份逻辑:主进程 fork,然后子进程执行落地任务,父进程继续响应请求,备份期间,系统变更量很少,单个kv的byte在64btes以内,变更的tps在100以下。
2 os版本与thp
线上Linux内核2.6.38 ——2.7,而 Linux 内核在2.6.38之后,默认开启Transparent hugepage,之前那些没法从复杂的hugepage中获得好处的应用,现在不需要做任何修改也可以得到性能改善,预计性能提升在10%左右。
3 内存去向分析
日志分析发现,整个备份过程持续10分钟,整个过程的修改kv的个数为 100*60*10=60000,有效内存变更 60000*64=约4M;
fork过程中,父进程变更是一个cow的过程,可以先算最极端情况:即每次变更的kv分散在一个page中,来进行计算最大值;
对于普通的page,应该占用的内存:4M * 4K=16G;所以这个过程最多占用16G;
系统默认开启了THP,每个page变成了2M,所以这个过程的最大占用内存 4M*2M=8192G;
由于kv的size很小,很多kv是在相同的page,所以实际占用内存在25G mem & 20G+ swap;
4 关闭THP
关闭THP,重启计数服务,百G数据的备份过程,更新毫无压力。
小结一下,fork 备份,主进程变更流程变为cow,而Linux默认启用THP,于是出现写放大(即便你更新1 byte,实际内存也可能需要新占用2M bytes),于是内存就成为了瓶颈,swap、响应慢,极端情况下被os干掉而crash 等都会出现。
5 如何关闭THP
1)boot时生效 修改grub.cfg
transparent_hugepage=never
2) runtime 是修改
# echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled
# echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag
6 More about THP
Transparent hugepage是一个hugepage管理的简化版,在Linux 2.6.38之后自动生效,只对anonymous mem生效,可以通过 grep -i AnonHugePages /proc/meminfo 查看实际使用情况。
对于普通的cache应用,默认的THP有性能提升,但如果有fork 且 fork的时间较长,需要观测资源占用情况,必要时关闭THP。
runtime 期间 关闭THP,之前已经分配的hugepage继续生效,只对新分配的page不再采用hugepage,os也不再scan & merge pages。
进程可以通过madvise 进行设置是否启用THP:
#includeint madvise(void *addr, size_t length, int advice);
参考:
https://access.redhat.com/solutions/46111
http://lwn.net/Articles/423584/
http://lwn.net/Articles/423592/