docker容器的内存问题排查(“内存丢失”)
场景描述
容器内可用内存远没有达到cgroup限制,就已经OOM(Out Of Memory Killer)。容器套餐4c8g,top看占内存最多的进程大约17m左右,总共100个,总内存也不到2g,但是memory.usage_in_bytes已经达到8g(free看也是一样),cache也只有几百兆,久而久之,cache所占内存也被耗尽,容器内进程oom,实际可用内存不到1g。在这记录下问题排查过程。
排查问题容器环境
由于达到oom的现场已经不在,现在使用下面的场景进行演示:
容器套餐4c8g,working_set内存6.8g(容器内一般用working_set来评内存使用情况,working_set=rss+活跃的cache),rss600m,cache1.7g,业务进程使用2g。目前working_set远小于rss+cache。
排查过程
- 进容器看看业务进程消耗资源
docker exec进到容器top后输入M(大写M),查看消耗内存最多的进程
top - 15:12:57 up 7 days, 1:00, 1 user, load average: 0.24, 0.08, 0.02
Tasks: 145 total, 1 running, 144 sleeping, 0 stopped, 0 zombie
Cpu(s): 1.0%us, 0.0%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 8192000k total, 7724968k used, 467032k free, 0k buffers
Swap: 0k total, 0k used, 0k free, 1745040k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 204 root 20 0 2527m 19m 3140 S 0.0 0.2 0:43.40 docker-qalarm
35382 nobody 20 0 306m 17m 9.8m S 0.0 0.2 0:20.51 php-fpm
35373 nobody 20 0 306m 17m 9984 S 0.0 0.2 0:20.88 php-fpm
35444 nobody 20 0 306m 17m 9964 S 0.0 0.2 0:20.55 php-fpm
35350 nobody 20 0 306m 17m 9936 S 0.0 0.2 0:20.44 php-fpm
35407 nobody 20 0 306m 17m 9976 S 0.0 0.2 0:20.22 php-fpm
35392 nobody 20 0 306m 17m 9924 S 0.0 0.2 0:20.33 php-fpm
35368 nobody 20 0 306m 17m 9916 S 0.0 0.2 0:20.22 php-fpm
35398 nobody 20 0 306m 17m 9908 S 0.0 0.2 0:20.27 php-fpm
35357 nobody 20 0 306m 17m 9912 S 0.3 0.2 0:20.94 php-fpm
35463 nobody 20 0 306m 17m 9912 S 0.0 0.2 0:20.22 php-fpm
35437 nobody 20 0 306m 17m 9900 S 0.0 0.2 0:21.09 php-fpm
35464 nobody 20 0 306m 17m 9896 S 0.0 0.2 0:20.46 php-fpm
35384 nobody 20 0 306m 17m 9888 S 0.3 0.2 0:19.90 php-fpm
35348 nobody 20 0 306m 17m 9876 S 0.0 0.2 0:20.53 php-fpm
35365 nobody 20 0 306m 17m 9880 S 0.0 0.2 0:20.71 php-fpm
35358 nobody 20 0 306m 17m 9868 S 0.0 0.2 0:20.42 php-fpm
35420 nobody 20 0 306m 17m 9892 S 0.0 0.2 0:19.88 php-fpm
35424 nobody 20 0 306m 17m 9864 S 0.0 0.2 0:20.52 php-fpm
35389 nobody 20 0 306m 17m 9872 S 0.0 0.2 0:20.18 php-fpm
35335 nobody 20 0 306m 17m 9908 S 0.0 0.2 0:20.84 php-fpm
35468 nobody 20 0 306m 17m 9912 S 0.3 0.2 0:20.58 php-fpm
[root@robot-speaker-e862e0-7c84fb65cd-whv5d /home/q/system/speaker-robot]# ps -ef | grep php-fpm|grep -v grep|wc -l
129
发现使用内存最多的php-fpm 进程用了17M,129个进程,一共使用内存2.1g。内存使用了7.4g、未使用450M、cache1.7g(我们使用了lxcfs做容器视图隔离,所以内存显示的是容器的真实情况),还有5g左右内存去哪了
2、进到内存容器cgroup
7af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]# ls
cgroup.clone_children memory.kmem.tcp.max_usage_in_bytes memory.oom_control
cgroup.event_control memory.kmem.tcp.usage_in_bytes memory.pressure_level
cgroup.procs memory.kmem.usage_in_bytes memory.soft_limit_in_bytes
memory.failcnt memory.limit_in_bytes memory.stat
memory.force_empty memory.max_usage_in_bytes memory.swappiness
memory.kmem.failcnt memory.memsw.failcnt memory.usage_in_bytes
memory.kmem.limit_in_bytes memory.memsw.limit_in_bytes memory.use_hierarchy
memory.kmem.max_usage_in_bytes memory.memsw.max_usage_in_bytes notify_on_release
memory.kmem.slabinfo memory.memsw.usage_in_bytes tasks
memory.kmem.tcp.failcnt memory.move_charge_at_immigrate
memory.kmem.tcp.limit_in_bytes memory.numa_stat
[root@docker123 /sys/fs/cgroup/memory/kubepods/burstable/pod6e726ccc-1d6f-11ea-851f-fa163e9a7739/45bb864dfe68379c6d2f07af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]#
- 查看 memory.usage_in_bytes
7af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]# cat memory.usage_in_bytes
7934582784
确实是7g多
- 查看内存使用情况memory.stat
7af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]# cat memory.stat
cache 1806925824
rss 622092288
rss_huge 287309824
mapped_file 20508672
swap 0
pgpgin 17583007
pgpgout 17135620
pgfault 48558141
pgmajfault 1180
inactive_anon 17465344
active_anon 628965376
inactive_file 1058193408
active_file 724385792
unevictable 0
hierarchical_memory_limit 8388608000
hierarchical_memsw_limit 16777216000
total_cache 1806925824
total_rss 622092288
total_rss_huge 287309824
total_mapped_file 20508672
total_swap 0
total_pgpgin 17583007
total_pgpgout 17135620
total_pgfault 48558141
total_pgmajfault 1180
total_inactive_anon 17465344
total_active_anon 628965376
total_inactive_file 1058193408
total_active_file 724385792
total_unevictable 0
没有占用内存特别大的项,也就是远没达到top所见。另外忘记说,上边单位都是字节
- 查看容器的内核内存使用量memory.kmem.usage_in_bytes
7af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]# cat memory.kmem.usage_in_bytes
5513891840
果然是5g
- 现在看下容器使用内核slab情况memory.kmem.slabinfo
7af95a9ac99dd32c8bc51aa4531f75a836d1b5e6c29]# cat memory.kmem.slabinfo
slabinfo - version: 2.1
...
taskstats 1960 1960 328 49 4 : tunables 0 0 0 : slabdata 40 40 0
xfs_ili 3945336 3945336 168 48 2 : tunables 0 0 0 : slabdata 82195 82195 0
xfs_btree_cur 1560 1560 208 39 2 : tunables 0 0 0 : slabdata 40 40 0
posix_timers_cache 16071 16071 248 33 2 : tunables 0 0 0 : slabdata 487 487 0
scsi_cmd_cache 1440 1440 448 36 4 : tunables 0 0 0 : slabdata 40 40 0
xfs_log_ticket 1760 1760 184 44 2 : tunables 0 0 0 : slabdata 40 40 0
cfq_queue 1400 1400 232 35 2 : tunables 0 0 0 : slabdata 40 40 0
inode_cache 2200 2200 592 55 8 : tunables 0 0 0 : slabdata 40 40 0
radix_tree_node 35635 39984 584 28 4 : tunables 0 0 0 : slabdata 1428 1428 0
bio-2 2040 2040 320 51 4 : tunables 0 0 0 : slabdata 40 40 0
fanotify_event_info 2920 2920 56 73 1 : tunables 0 0 0 : slabdata 40 40 0
blkdev_ioc 1560 1560 104 39 1 : tunables 0 0 0 : slabdata 40 40 0
xfs_inode 3959772 3959772 960 34 8 : tunables 0 0 0 : slabdata 116478 116478 0
Acpi-ParseExt 2240 2240 72 56 1 : tunables 0 0 0 : slabdata 40 40 0
...
可以看出关于文件元数据缓存就占了4g多,上图第三列是对象数量,第四列是对象大小,所以xfs_inode占用内存=3959772 * 960 /1024/1024/1024,约等于3.5g,xfs_ili 0.7g,这已经4g多了。所以基本可以断定是业务进程操作文件多过导致
- 查看容器内是否有大量小文件
[root@robot-speaker-e862e0-7c84fb65cd-whv5d /data/php/session]# ls -lR | grep "^-"| wc -l
3941117
可见session文件数与slab中的xfs_inode基本相当,所以可以断定罪魁祸首在此
- 随着session文件越来越多,xfs_inode占用slab内存越来越多,不可回收SUnreclaim也会越来越大,所以最终会导致可用内存越来越少
验证结果
经过与业务沟通,他们清理的大量session文件后,slab内存明显降下来了。
image.png
结论
- 业务应尽可能的避免这种上百万级别的小文件
- 更优雅的方式是限制容器内可用内核缓存的比例(还在尝试)
参考文档
https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/6/html/resource_management_guide/sec-memory
https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html
https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html