如何排查定位Kubernetes Pod中内存占用最高的进程
Pod内存逼近1Gi限制排查方案
修正htop使用方式,避免漏检进程
你之前用htop没查到高负载进程,大概率是默认排序、显示字段不全导致的:
- 进入容器执行
htop后按F6,优先选择按M_RESIDENT(常驻内存)排序,不要默认按CPU排;按F2进入设置,在显示列中追加CGROUP、M_SHARE、SWAP字段,避免漏算共享内存、归属cgroup有偏差的进程。 - 针对短生命周期进程(比如定时拉起跑完就退的脚本),htop默认3秒刷新间隔很容易漏,可以执行
top -b -d 1 -n 30 > /tmp/proc_mem.log,连续30秒每秒导出一次全进程内存快照,事后检索日志里的高内存条目即可。
精确统计每个进程的实际内存占用
和cgroup统计口径对齐的进程内存统计方式,不会出现htop/top统计值和cgroup监控值对不上的问题:
在容器内执行以下脚本,会按实际占用从高到低输出Top20进程的内存数据,其中PSS是按比例分摊共享内存后的真实占用,比RSS更准确(不会把共享库内存重复计算到每个进程头上):
for pid in $(ls /proc | grep -E '^[0-9]+$'); do if [ -f /proc/$pid/smaps_rollup ]; then pss=$(awk '/Pss/ {print $2}' /proc/$pid/smaps_rollup) rss=$(awk '/Rss/ {print $2}' /proc/$pid/smaps_rollup) cmd=$(cat /proc/$pid/comm 2>/dev/null) echo "$pss KB PSS | $rss KB RSS | PID $pid | PROCESS $cmd" fi done | sort -nr | head -20
如果容器内核版本低于4.14没有
smaps_rollup文件,把上面脚本里的smaps_rollup换成smaps即可,只是统计速度会慢一点。
所有进程的PSS累加值,和memory.stat里的进程相关内存占用基本一致,不会漏统计。
排查htop看不到的非进程内存占用
这部分是最容易踩的坑,占内存但不会显示在任何用户进程的资源统计里:
- 页缓存占用:执行
grep -E 'cache|dirty|writeback' /sys/fs/cgroup/memory/memory.stat,如果cache值占总内存30%以上,说明是大文件读写、日志高频写入产生的页缓存没回收,这部分内存理论上可回收,但如果没触发cgroup内存回收阈值就会先撞到1Gi限制。 - tmpfs/共享内存占用:执行
df -h -t tmpfs查看容器内所有tmpfs挂载点(包括/dev/shm、/tmp、Pod的emptyDir挂载目录)的使用量,这部分占用会被算到memory.stat的cache指标里,不会体现在进程RSS中,往emptyDir写大文件未清理是这类问题的高发原因。 - 内核态内存占用:先看slab占用,执行
grep slab /sys/fs/cgroup/memory/memory.stat,slab_reclaimable是内核缓存的目录项、inode等可回收结构,多由大量小文件读写触发;slab_unreclaimable如果持续上涨,大概率是内核层面的内存泄漏,需要结合节点日志排查。另外还要算上内核栈、socket缓冲区占用,这部分值一般不大,但高并发场景下socket缓冲区涨起来也会占几百MB内存。
memory.stat核心指标对照
不用啃全量文档,排查问题只需要记几个核心字段:
rss:所有用户进程的匿名内存、栈内存占用,不含页缓存cache:页缓存+tmpfs+共享内存总占用slab:内核slab分配器占用,分可回收/不可回收两部分inactive_file:非活跃文件缓存,是内存回收时最先释放的部分- cgroup实际总内存占用 =
rss+cache+slab+kernel_stack+sock(socket缓冲区),和监控看到的内存使用率完全对齐。
补充排查点
- 不要漏查同Pod的sidecar容器:日志采集、服务网格等sidecar如果出现内存泄漏,也会占Pod的总内存配额,可以先看每个容器的工作集内存指标,定位到具体容器后再进容器执行上面的排查步骤。
- 检查僵尸进程:执行
ps aux | grep Z,僵尸进程本身不占用户态内存,但会持有内核资源,数量过千时也会消耗可观的内核栈内存。
内容的提问来源于stack exchange,提问作者Dhody Rahmad Hidayat
相关产品推荐
相关产品推荐

