问题背景

线上业务集群迁移到新机器,在运行一段时间后,发现新机器不是很稳定,各个机器的 cpu idle 和耗时会出现一些尖峰式的震荡,idle 最低的时候会压到0,同时也会出现不少超时请求,看起来,机器在那一瞬间像被卡住了一样,但又能较快恢复。如下图所示

6F205DED-DBB5-412F-AB47-BBC944D7F36A.png

与 NUMA 和 NUMA balancing 的问题不同,之前出问题的机器会比较稳定的耗时长,idle 低,性能差,而这些机器则是不稳定出现,而且出问题的时间很短,很难抓住现场。而且这些机器所在机房本身又有超电风险,又加开了睿频,一时间,我们也很难确定问题是来自于外部还是来自于机器本身。

问题解决

问题的结局也很偶然,是有同学在测试其它业务的时候发现系统 buff/cache 过高,而他们的业务需要申请大量内存,当 buff/cache 填满之后,系统性能明显下降,手动清理之后恢复。看表象和我们的情况不太一致,我们的业务也不像他们那样大量使用内存,抱着试一试的态度,也看了一眼系统 buff/cache 的情况,还真发现两者存在正相关的关系(当然不是所有 buff/cache 高的机器都有抖动的情况,而是抖动的机器绝大多数都是 buff/cache 高),如下图所示:

A8F5039A-EDDC-4CED-805A-B3F751B64793.png

手动释放 cache 也比较简单,直接执行echo 3 > /proc/sys/vm/drop_caches命令即可清除,注意在如上面这样 buff/cache 巨大的情况下,清理会执行较长时间,也会占用一个 cpu,不建议在高峰期操作,对正常机器,这个操作也是流量有损的。另:官方文档里强调这个操作可能会导致严重性能问题,不建议在生产环境未经实验就开始使用。

至于为何会有问题,Tuning kernel memory for performance这篇文章里会有介绍,在此不班门弄斧。问题大致原因是,虽然 buff/cache 被认为是可用的内存,但使用时,也需要甄别那些块是可以释放使用的,因此当所有内存都被 buff/cache 占用后,在某些情况下,清理释放这些内存块也需要大量占用 cpu 资源导致系统响应变慢。

应对这个问题的简单方法是写个定时任务定时清理内存,但这样治标不治本,另外一种较持久的方法是设置保留内存的大小,在上面文章的 solution 里也有介绍,设置/proc/sys/vm/min_free_kbytes的大小即可,一般设置内存大小的10%为保留内存,当系统发现 free 的内存小于该值的时候,会开始寻找可以释放的 buff/cache,使得 free 的值在保留值之上。不过注意这样的方式机器重启之后就会失效,一劳永逸的方法是修改/etc/sysctl.conf,修改vm.min_free_kbytes的值即可。另外文中提到,对于耗时敏感的服务,任何程度的 swap 都会导致性能受损,可以将vm.swappiness设置为0,不使用 swap。

再次强调,生产环境直接修改这些值可能会导致严重后果,请先在灰度环境或者流量低峰测试之后再进行操作。建议详细阅读Tuning kernel memory for performance这篇文章,正确理解相关参数的含义。