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

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

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

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

[[236276]]

我们可以用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退出。

责任编辑:武晓燕 来源: 潇洒的云世界
相关推荐

2020-10-22 13:49:37

Docker容器僵死进程

2016-01-11 10:29:36

Docker容器容器技术

2019-07-16 14:44:52

DockerMySQL操作系统

2019-12-24 08:49:06

容器Docker网络

2010-02-04 09:26:34

Linux vmsta

2022-01-10 17:41:31

内存结构PostgreSQL

2023-09-01 11:34:41

2023-08-29 10:50:25

2018-10-12 11:11:39

Oracle内存结构

2020-01-09 15:28:30

KubernetesDocker:容器

2023-09-15 10:15:43

Docker网络

2017-03-20 14:51:33

2015-03-26 17:13:17

云计算数据中心IDC

2020-07-16 07:52:09

Docker容器数据库

2015-02-13 10:21:11

dockerubuntu解决方案

2018-06-26 15:58:39

进程内缓存缓存数据

2016-05-20 09:58:58

Java内存限制LXC

2014-12-15 10:40:40

DockerSwarm集群管理

2019-05-14 14:27:36

KubernetesDocker存储

2016-10-08 15:42:02

ElasticsearcAdvisorDocke
点赞
收藏

51CTO技术栈公众号