Featured image of post docker容器内存增长排查

docker容器内存增长排查

背景

最近在把服务改造成docker容器化,但是在压测中发现,使用docker stats查看容器情况,发现内存一直在增长, 但是使用ps -aux查看的RSS(实际物理内存)内存占用是固定的,没有增长。针对此问题,现记录一下排查过程。

主机系统是CentOS 7.9.2009docker版本是26.1.4

排查过程

基础知识

docker stats统计的是cgroup memory.usage_in_bytes,主要包括:

  • RSS
  • 程序未释放但是占用的虚拟内存(anonymous memory)
  • Page Cache(文件缓存)
  • Shmem(共享内存)
  • tmpfs/overlayfs 缓冲区
  • Mapped文件
  • 网络相关的buffer
  • 内核为容器分配的内存

ps -aux查看的就是RSS(实际物理内存)

开始排查

  1. 查看容器的内存实际占用情况
1
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.stat 

需要注意的是container_id是完整的,不是缩写。 我们使用docker ps查看容器id时,默认显示的是缩写的id。

第一次数据为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cache 626470912
rss 32657408
rss_huge 20971520
mapped_file 0
swap 69632
pgpgin 232273
pgpgout 76463
pgfault 111370
pgmajfault 45
inactive_anon 26267648
active_anon 6389760
inactive_file 278405120
active_file 348065792
unevictable 0
hierarchical_memory_limit 9223372036854771712
hierarchical_memsw_limit 9223372036854771712
total_cache 626470912
total_rss 32657408
total_rss_huge 20971520
total_mapped_file 0
total_swap 69632
total_pgpgin 0
total_pgpgout 0
total_pgfault 0
total_pgmajfault 0
total_inactive_anon 26267648
total_active_anon 6389760
total_inactive_file 278405120
total_active_file 348065792
total_unevictable 0

第二次的数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cache 667144192
rss 32940032
rss_huge 20971520
mapped_file 0
swap 69632
pgpgin 243250
pgpgout 77441
pgfault 113316
pgmajfault 45
inactive_anon 26267648
active_anon 6672384
inactive_file 291627008
active_file 375517184
unevictable 0
hierarchical_memory_limit 9223372036854771712
hierarchical_memsw_limit 9223372036854771712
total_cache 667144192
total_rss 32940032
total_rss_huge 20971520
total_mapped_file 0
total_swap 69632
total_pgpgin 0
total_pgpgout 0
total_pgfault 0
total_pgmajfault 0
total_inactive_anon 26267648
total_active_anon 6672384
total_inactive_file 291627008
total_active_file 375517184
total_unevictable 0

统计两次的差异为:

字段 snapshot1 (MB) snapshot2 (MB) diff (MB)
cache(缓存) 597.652 636.128 38.476
rss(常驻内存) 31.129 31.426 0.297
pgpgin(内存页读入次数) 0.222 0.232 0.010
pgpgout(内存页写出次数) 0.073 0.074 0.001
pgfault(缺页次数) 0.106 0.108 0.002
active_anon(匿名活跃页) 6.094 6.362 0.268
inactive_file(文件未活跃页) 265.583 278.000 12.417
active_file(文件活跃页) 331.942 358.000 26.058
total_cache(总缓存) 597.652 636.128 38.476
total_rss(总常驻内存) 31.129 31.426 0.297
total_active_anon(总匿名活跃) 6.094 6.362 0.268
total_inactive_file(总文件未活跃) 265.583 278.000 12.417
total_active_file(总文件活跃) 331.942 358.000 26.058

可以看到:

cache/total_cache: 增长了38.476MB,

inactive_file: 增长了12.417MB,

active_file: 增长了26.058MB,总共就38.476MB, 说明文件cache增多。

rss/total_rss: 增长了0.297MB,可以忽略。

这种 cache的增长原因是:容器内频繁访问文件,包括:

  • 日志文件
  • overlay2 文件层
  • 配置文件
  • 静态文件
  • 访问volume

这个是正常情况,内核会在内存不足时,自动回收。

但是内存一直增长不是正常现象,需要进一步排查原因。

  1. 排查cache增长的原因

在主机上临时清除缓存:

1
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches

执行之后,可以发现docker stats会瞬间下降到RSS的大小。 因为我把日志挂载到了主机上, 基本可以确定是日志文件导致的cache增长。

  1. 如何解决

原本是修改日志组件, 每次Write之后就Sync到磁盘, 但是改完之后效果不大,Page Cache还是会增长。

采用的方案有两种:

  1. 修改系统的内存回收机制:
1
2
3
4
5
/etc/sysctl.conf
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.dirty_expire_centisecs = 500
vm.dirty_writeback_centisecs = 100

sysctl -p 生效

效果不太明显,增长的速度只是慢了一些,但是还是一直增长。

  1. 是在docker-compose.yaml中添加mem_limitmem_reservation参数, 限制容器内存占用:
1
2
3
4
5
6
deploy:
      resources:
        limits:
          memory: 40M
        reservations:
          memory: 20M

在测试中发现,设置的最大内存为40M,程序的RSS占用为37M, 当docker stats增长还没到40M时(大概35M), 会主动回收Page Cache。导致docker stats的内存不会增长到40M

总结

  1. RSS的大小不增长时,可以认定服务是没有内存泄漏问题。
  2. Page Cache的大小增长时,这类就需要设置系统层面上的内存回收机制, 限制容器内存占用,让其自动回收。
本博客已稳定运行
发表了72篇文章 · 总计126.91k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计