缘起
容器监控显示内存已被撑爆,但进入容器查看进程列表,却找不到任何进程在大量消耗内存。使用 awk 将所有容器进程的 RSS 相加,结果远低于内存上限。这究竟是什么原因导致的?
分析
第一反应:难道是 docker stats 的计算出了问题?
进入 /sys/fs/cgroup/memory/docker/xxxxx/ 查看 memory.usage,数值与监控一致——计算并没有错误。那么就必须考虑另一个方向:系统内存中有一部分会被 buffer 和 cache 占用,Linux 内核会将这部分计入“已使用”内存。对于容器而言,是否也会出现类似的“误算”?而且很有可能某个容器触发的文件缓存(cache)被归到了它自己的头上。
验证方法非常简单:在容器内执行 dd 生成一个大文件。果然,dd 之后 docker stats 显示的已用内存立刻飙升。接着在宿主机上执行 echo 3 > /proc/sys/vm/drop_caches,容器监控的已用内存又降了回去。原因逐渐清晰。
问题
对于宿主机,计算内存占用时可以用“已用内存”减去 cache/buffer 来得到真实使用量。那么对于容器呢?如果不减去它自身引发的 cache/buffer,就会导致误报警。实际测试发现:dd 产生的文件缓存所占用的内存,会被计入 inactive_file 这个指标。这意味着,如果监控报警规则只盯着总内存,很可能就会被 cache 部分所欺骗。
