k8s怎么了?为什么容器内存占用居高不下,频频 OOM?( 二 )

查看容器的 Linux 内核版本:
$ uname -aLinux xxx-xxx-99bd5776f-k9t8z 3.10.0-693.2.2.el7.x86_64但 MADV_FREE 的策略改变 , 需要 Linux 内核在 4.5 及以上(详细可见 go/issues/23687) , 显然不符合 , 因此也将其从猜测中排除 。
猜想四:监控/判别条件有问题会不会是 Grafana 的图表错了 , Kubernetes OOM Kill 的判别标准也错了呢 , 显然不大可能 , 毕竟我们拥抱云 , 阿里云 Kubernetes 也运行了好几年 。
k8s怎么了?为什么容器内存占用居高不下,频频 OOM?文章插图
但在这次怀疑中 , 我了解到 OOM 的判断标准是 container_memory_working_set_bytes 指标 , 因此有了下一步猜想 。
猜想五:容器环境的机制既然不是业务代码影响 , 也不是 Go Runtime 的直接影响 , 那是否与环境本身有关呢 , 我们可以得知容器 OOM 的判别标准是 container_memory_working_set_bytes(当前工作集) 。
而 container_memory_working_set_bytes 是由 cadvisor 提供的 , 对应下述指标:
k8s怎么了?为什么容器内存占用居高不下,频频 OOM?文章插图
从结论上来讲 , Memory 换算过来是 4GB+ , 实锤 。 接下来的问题就是 Memory 是怎么计算出来的呢 , 显然和 RSS 不对标 。
原因从 cadvisor/issues/638 可得知 container_memory_working_set_bytes 指标的组成实际上是 RSS + Cache 。 而 Cache 高的情况 , 常见于进程有大量文件 IO , 占用 Cache 可能就会比较高 , 猜测也与 Go 版本、Linux 内核版本的 Cache 释放、回收方式有较大关系 。
k8s怎么了?为什么容器内存占用居高不下,频频 OOM?文章插图
而各业务模块常见功能 , 如:

  • 批量图片解压缩 。
  • 批量二维码生成 。
  • 批量上传渲染后图片 。
  • 批量 PDF 生成 。
  • …只要是涉及有大量文件 IO 的服务 , 基本上是这个问题的老常客了 , 这类服务基本写一个中一个 。
显然这是一个混合问题 , 像其它单纯操作为主的业务服务就很 “正常” , 不会出现内存居高不下 。
解决方案在本场景中 cadvisor 所提供的判别标准 container_memory_working_set_bytes 是不可变更的 , 也就是无法把判别标准改为 RSS , 因此我们只能考虑掌握主动权 。
首先是做好做多级内存池管理 , 可以缓解这个问题的症状 。 但这存在难度 , 从另外一个角度来看 , 你怎么知道什么时候在哪个集群上会突然出现这类型的服务 , 何况开发人员的预期情况参差不齐 , 写多级内存池写出 BUG 也是有可能的 。
让业务服务无限重启 , 也是不现实的 , 被动重启 , 没有控制 , 且告警 , 存在风险 。
因此为了掌握主动权 , 可以在部署环境可以配合脚本做 “手动” HPA , 当容器内存指标超过约定限制后 , 起一个新的容器替换 , 再将原先的容器给释放掉 , 就可以在预期内替换且业务稳定了 。
k8s怎么了?为什么容器内存占用居高不下,频频 OOM?文章插图
总结虽然这问题时间跨度比较长 , 整体来讲都是阶段性排查 , 本质上可以说是对 Kubernetes 的不熟悉有关 。 但综合来讲这个问题涉及范围比较大 , 因为内存居高不下的可能性有很多种 , 要一个个排查 , 开发权限有限 , 费时费力 。
基本排查思路就是:
  1. 怀疑业务代码(PProf) 。
  2. 怀疑其它代码(PProf) 。
  3. 怀疑 Go Runtime。
  4. 怀疑工具 。
  5. 怀疑环境 。
非常感谢在这大段时间内被我咨询的各位大佬们 , 感觉就是隔了一层纱 , 捅穿了就很快就定位到了 。
大家如果有其它解决方案也欢迎随时沟通 。
作者:煎鱼
【k8s怎么了?为什么容器内存占用居高不下,频频 OOM?】出处: