当前位置:   article > 正文

k8s故障排查个案:当Pod内存持续增长,OOM问题如何解决?_pod的缓存内存

pod的缓存内存

pod 运行一段时间后,内存持续增长,甚至 oom 的情况.

动机

容器化过程中,我们经常会发现 kubernetes 集群内 pod 的内存使用率会不停持续增长,加多少内存吃多少内存,如果对 cgroup 内存的构成不是很清楚的情况下,单纯看监控看不出什么问题。

经过一番查阅,目前总结出大致有 2 种导致这种情况的场景。

  1. 内存泄露

  2. io 缓存

案例分析

我们先从内存泄露分析,刚好手头有个 pod 也是这种情况。

内存泄露

进入对应的 pod 内部。我们先看看它用了多少内存,prometheus 也是取这个值做为容器的内存使用率的

  1. # cat /sys/fs/cgroup/memory/memory.usage_in_bytes
  2. 4192538624
  3. # bytes转GB,结果是 3.9GB

我们查看 grafana ,内存使用率的采集结果与 cgroup 里面的记录一致。

/kubernetes%E6%8E%92%E9%94%99-pod-oom-%E5%86%85%E5%AD%98%E6%8C%81%E7%BB%AD%E5%A2%9E%E9%95%BF/pod%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E7%8E%87%E7%9B%91%E6%8E%A7.png

pod内存使用率监控

我们拉长一下记录看看。

/kubernetes%E6%8E%92%E9%94%99-pod-oom-%E5%86%85%E5%AD%98%E6%8C%81%E7%BB%AD%E5%A2%9E%E9%95%BF/pod%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E7%8E%87%E7%9B%91%E6%8E%A7%E6%8B%89%E9%95%BF.png

pod内存使用率监控拉长

很明显就是发生内存泄露了 ,接下来,我们看看 pod 容器内内存记录。

  1. # cat /sys/fs/cgroup/memory/memory.stat
  2. cache 36900864
  3. rss 4205309952
  4. rss_huge 2837446656
  5. shmem 0
  6. mapped_file 1351680
  7. dirty 1081344
  8. writeback 0
  9. swap 0
  10. workingset_refault_anon 0
  11. workingset_refault_file 20815872
  12. workingset_activate_anon 0
  13. workingset_activate_file 12029952
  14. workingset_restore_anon 0
  15. workingset_restore_file 8785920
  16. workingset_nodereclaim 0
  17. pgpgin 5688606
  18. pgpgout 5778093
  19. pgfault 2878062
  20. pgmajfault 0
  21. inactive_anon 4224827392
  22. active_anon 0
  23. inactive_file 9543680
  24. active_file 25153536
  25. unevictable 0
  26. hierarchical_memory_limit 4294967296
  27. hierarchical_memsw_limit 4294967296
  28. total_cache 36900864
  29. total_rss 4205309952
  30. total_rss_huge 2837446656
  31. total_shmem 0
  32. total_mapped_file 1351680
  33. total_dirty 1081344
  34. total_writeback 0
  35. total_swap 0
  36. total_workingset_refault_anon 0
  37. total_workingset_refault_file 20815872
  38. total_workingset_activate_anon 0
  39. total_workingset_activate_file 12029952
  40. total_workingset_restore_anon 0
  41. total_workingset_restore_file 8785920
  42. total_workingset_nodereclaim 0
  43. total_pgpgin 5688606
  44. total_pgpgout 5778093
  45. total_pgfault 2878062
  46. total_pgmajfault 0
  47. total_inactive_anon 4224827392
  48. total_active_anon 0
  49. total_inactive_file 9543680
  50. total_active_file 25153536
  51. total_unevictable 0

上面获取内存记录,我们主要关心:

total_cachetotal_rsstotal_inactive_anontotal_active_anontotal_inactive_filetotal_active_file

分别代表的意思:

  • total_cache:表示当前pod缓存内存量

  • total_rss:表示当前应用进程实际使用内存量

  • total_inactive_anon:表示匿名不活跃内存使用量

  • total_active_anon:表示匿名活跃内存使用量,jvm堆内存使用量会被计算在此处

  • total_inactive_file:表示不活跃文件内存使用量

  • total_active_file:表示活跃文件内存使用量

rss 确实是使用了 3.9GB 的量,确实是 pod 容器的真实使用,那么基本就验证了要么程序确实内存不够,要么就是内存泄露了。

io 缓存

除了上面那种内存泄露的场景外,还有一种是 io 缓存导致的内存虚高。如下,wss 比 rss 高出不少,这还不算极端的,只是拿出这个举个例子。

/kubernetes%E6%8E%92%E9%94%99-pod-oom-%E5%86%85%E5%AD%98%E6%8C%81%E7%BB%AD%E5%A2%9E%E9%95%BF/pod%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E7%8E%87%E7%9B%91%E6%8E%A7io.png

pod内存使用率监控

然后,我们来看下容器内存指标的组成结构。

  • container_memory_working_set_bytes

  • container_memory_rss

容器当前使用内存量: container_memory_usage_bytes = total_cache + total_rss

容器当前使用缓存内存: total_cache = total_inactive_file + total_active_file

container_memory_working_set_bytes:container_memory_working_set_bytes = container_memory_usage_bytes - total_inactive_file

带入上面两个公式,容器的工作集的等式可以拆解为:

  1. container_memory_working_set_bytes
  2. = container_memory_usage_bytes - total_inactive_file
  3. = total_cache + total_rss - total_inactive_file
  4. = total_inactive_file + total_active_file + total_rss - total_inactive_file
  5. = total_active_file + total_rss
  • total_rss 为应用真实使用内存量,正常情况下该指标数值稳定,那为何该指标会持续上升而且一直维持很高呢?其实问题就出现在 total_active_file 上。

  • Linux 系统为了提高文件读取速率,会划分出来一部分缓存内存,即 cache 内存,这部分内存有个特点,当应用需要进行 io 操作时,会向 Linux 申请一部分内存,这部分内存归属于操作系统,当应用io操作完毕后,操作系统不会立即回收,当操作系统认为系统剩余内存不足时,才会主动回收这部分内存。

  • container_memory_working_set_bytes 指标升高一部分是应用本身内存使用量增加,另一部分就是进行了 io 操作,total_active_file 升高,该指标异常一般都是应用进行了io相关操作。

总结

知道这些情况后,然后就是解决方法:

  1. 如果是频繁写日志到磁盘或输出日志到标准输出的场景,可以紧张日志输出到标准输出,日志落盘做轮转,比如 50-100MB 一个文件做切割,保留最近几个日志文件即可。昨晚这些后,container_memory_working_set_bytes 的使用率会肉眼可见的回落。

  2. 如果是内存计算比较频繁的服务,可以现在程序的可用内存,比如 jvm ,10G 的 pod 内存,限制程序使用 8.5GB 的的内存,现在对外内存最大使用值 1.5GB,这样就可以预留足够的内存防止 pod oom 了。只是打个比方,具体还得根据真实场景所需设置。

  3. wss的值:container_memory_working_set_bytes = total_active_file + total_rss

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/318373
推荐阅读
相关标签
  

闽ICP备14008679号