|
|
|
|
移动端

Docker和容器内进程内存计算差别

生产环境上了大规模容器集群后,肯定需要对容器进行监控,容器的编排我们采用了Kubernetes,监控前期采用了Weave Scope,后期采用了cAdvisor+Heapster+InfluxDB的方案,刚开始监控感觉并没有什么异常,但是集群运行久了之后,发现监控的指标和预想的并不一样。

作者:潇洒来源:潇洒的云世界|2018-07-12 10:33

【新品产上线啦】51CTO播客,随时随地,碎片化学习

生产环境上了大规模容器集群后,肯定需要对容器进行监控,容器的编排我们采用了Kubernetes,监控前期采用了Weave Scope,后期采用了cAdvisor+Heapster+InfluxDB的方案,刚开始监控感觉并没有什么异常,但是集群运行久了之后,发现监控的指标和预想的并不一样。

我们有对应的Java应用跑在容器中,每个Container的资源限制了4C16G(看起来和虚机一样夸张),JVM设置了Xmx2G的限制,但是发现有些容器的内存使用率一直在16G左,完全没有释放出来。Weave Scope和Heapster监控采集到的指标都是一样的,但是实际登录容器后发现JVM才用了800M不到。Weave Scope上其实可看到container和container内process的内存消耗,这个和实际登录容器看到的是一样的结果,如下图(剩余的那些sleep等进程其实占内存很少,忽略不计)

我们可以用docker stats查看对应容器的资源消耗,看到内存使用率在16G左,如下图

其实容器内部就是Linux对于内存的计算方式,我Baidu了一下发现Linux和Docker对于容器内存的计算是有差异的,Linux中buffer/cache是不计算进used memory的,所以下图中total=free+used+buff/cache,free命令的数据来源于/proc/meminfo

Docker本身的内存要通过cgroup文件中相关数据计算,我们进入对应容器的cgroup目录中,我们的容器以Pod为最小单位运行在Kubernetes环境中,所以路径在/sys/fs/cgroup/memory/kubepods下,后面跟着Pod的唯一标识和container的唯一标志

  1. /sys/fs/cgroup/memory/kubepods/pod2534673f-68bd-11e8-9fff-325ce3dddf77/245ac9f74c34b666ba14fadab30ef51c0f6259324b4b2f100e9b6b732b4c0933 

在该目录中有一个memory.limit_in_bytes文件,这个就是Kubernetes的YAML文件通过resource.limit将值传递给Docker API下发的内存限制,cat查看为17179869184,单位Byte,转换后刚好为16G;然后我们看到有一个memory.usage_in_bytes,为当前容器的内存使用量,cat查看为17179824128,转换后15.9999G,Docker的原生监控,就是我们在用的这些Weave Scope和Heapster其实都是查询这个memory.usage_in_bytes的值;那么我们怎么推算出实际容器中应用消耗的内存总量呢,我们需要查看该目录下的memory.stat文件,cat看到如下内容

  1. [root@docker 245ac9f74c34b666ba14fadab30ef51c0f6259324b4b2f100e9b6b732b4c0933]# cat memory.stat 
  2.  
  3. cache 15749447680 
  4. rss 817262592 
  5. rss_huge 715128832 
  6. mapped_file 3653632 
  7. swap 0 
  8. pgpgin 59308038 
  9. pgpgout 55485716 
  10. pgfault 97852409 
  11. pgmajfault 1048 
  12. inactive_anon 0 
  13. active_anon 817238016 
  14. inactive_file 7932751872 
  15. active_file 7816630272 
  16. unevictable 0 
  17. hierarchical_memory_limit 17179869184 
  18. hierarchical_memsw_limit 34359738368 
  19. total_cache 15749447680 
  20. total_rss 817262592 
  21. total_rss_huge 715128832 
  22. total_mapped_file 3653632 
  23. total_swap 0 
  24. total_pgpgin 59308038 
  25. total_pgpgout 55485716 
  26. total_pgfault 97852409 
  27. total_pgmajfault 1048 
  28. total_inactive_anon 0 
  29. total_active_anon 817238016 
  30. total_inactive_file 7932751872 
  31. total_active_file 7816630272 
  32. total_unevictable 0 

对其中常用项的解释如下表

实际Container中实际内存使用量real_used =memory.usage_in_bytes - (rss + active_file + inactive_file),但是一个resource.limit为16G的Container,JVM应用只是用了几百兆,但监控查到使用了16G,多出的15G用在哪里。我们查询了InfluxDB数据库,拉出了Pod的监控历史,发现有一个时间点,内存使用率从16G一下子掉到了11G,并且在1分钟后上升到了16G,此时间点通过工作记录发现是有清容器日志的操作,应用将日志通过文件的形式写在宿主机的文件系统中,我们找了测试环境尝试,将一个内存消耗为7G的Container的5G日志清掉,docker stats可以看到Container的内存使用率一下子掉到了4G,并且active_file和inactive_flie都有大幅度的下降,这里为什么清了日志内存使用率只掉到4G,因为我们还有其他的写文件日志没有清,以及Container本身输出在Stdout的json.log。这样的高内存使用率长达1周,但是我们发现并没有让容器因为OOM(Out-Of-Memory)而退出,推算出容器中的Cache其实会根据实际的内存分配量而使用,并不像程序为超额使用导致容器OOM退出。

【编辑推荐】

  1. Oracle 关系型分布式内存数据库
  2. 数据库不适合Docker及容器化的7大原因
  3. AI是如何影响计算机内存系统的?
  4. 作为 Java 开发者,你需要了解的堆外内存知识
  5. 容器云存储的需求考量与方案选择
【责任编辑:武晓燕 TEL:(010)68476606】


点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

框架设计(第2版)CLR Via C#

作为深受编程人员爱戴和尊敬的编程专家,微软.NET开发团队的顾问,本书作者Jeffrey Richter针对开发各种应用程序(如Web Form、Windows For...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊