容器内存一路涨到 OOM,我没改一行业务代码,靠 eBPF 把"贼"揪出来了

简介: 容器内存一路涨到 OOM,我没改一行业务代码,靠 eBPF 把"贼"揪出来了

容器内存一路涨到 OOM,我没改一行业务代码,靠 eBPF 把"贼"揪出来了

我是 Echo_Wish。前阵子半夜被叫起来,一个跑在 K8s 里的服务每隔几个小时就被 OOMKilled 一次,重启完内存又从头爬坡,像西西弗斯推石头。

业务方的第一反应是:"能不能给个 heap dump?" 我说,这是 Python 加 C 扩展的混合服务,heap dump 只能看到 Python 那一层,真正涨的地方它看不见。

这就是我今天想聊的:很多时候,你没法直接进应用里排查,那就绕着走,从旁边的系统层面把它盯死。 eBPF 干的就是这个活。

第一步:先别急着上工具,先问"涨的是哪块内存"

我见过太多人一上来就 memleak,结果查了半天发现压根不是泄漏。先看容器的内存到底怎么涨的:

# 找到容器在宿主机上的 PID
PID=$(crictl inspect --output go-template --template '{
   {.info.pid}}' <container_id>)

# 看 cgroup 层面的内存构成
cat /sys/fs/cgroup/kubepods.slice/.../memory.stat | egrep "^(anon|file|slab|sock) "

# 看进程自己的 RSS 变化
while true; do grep -E "VmRSS|RssAnon" /proc/$PID/status; sleep 10; done

结果很关键:anon 持续涨,file 和 slab 基本不动。这说明是匿名内存在涨,也就是堆和 mmap 出来的那种,page cache 没背锅。方向对了,才轮到 eBPF 登场。

第二步:不碰应用,从系统调用层面"数人头"

应用层我进不去,但应用要内存,总得向内核要。内核这扇门,eBPF 守得住:

bpftrace -e '
tracepoint:syscalls:sys_enter_mmap /pid == '$PID'/ {
    @mmap_bytes[ustack(6)] = sum(args->len);
}
tracepoint:syscalls:sys_enter_munmap /pid == '$PID'/ {
    @munmap_bytes = sum(args->len);
}
interval:s:60 { exit(); }
'

跑一分钟,对比 mmap 和 munmap 的量。我当时看到的是:申请的远多于释放的,而且绝大部分集中在同一条用户态调用栈上。 栈顶落在一个叫 decode_frame 的函数里,属于一个第三方 C 库。

这就是"间接"的好处:我没有去猜应用逻辑,而是让内核告诉我谁在要内存。

第三步:再用 page fault 交叉验证

只看 mmap 有个坑:申请了不代表用了。真正吃掉物理内存的是缺页中断:

bpftrace -e '
software:page-faults:1 /pid == '$PID'/ {
    @faults[ustack(8)] = count();
}
interval:s:30 { exit(); }
'

两份数据的热点栈对上了,我才敢下结论。单一证据别轻易定罪,两条独立线索指向同一个人,才叫实锤。

第四步:最后上 memleak 确认"只借不还"

/usr/share/bcc/tools/memleak -p $PID -T 5 60

输出里 decode_frame 那条栈,未释放字节数一直在涨。回头翻代码,原来是一个异常分支提前 return,漏掉了 free(buf)。线上遇到畸形数据才会走进去,所以泄漏很慢,慢到你以为是"正常增长"。

一个容易被忽略的反面案例

另一个服务我也遇到过 RSS 暴涨,同样的流程跑下来,发现 malloc 和 free 是基本平衡的。罪魁祸首是 glibc 的 arena 碎片:多线程下每个线程各占一个 arena,释放的内存还回不去操作系统。

# 不改代码,一个环境变量就能验证
MALLOC_ARENA_MAX=2

加上之后内存曲线立刻平了。这类问题如果你一上来就认定"泄漏",会白白追几天。

聊点心里话

干了这么多年运维,我越来越觉得:

  1. 排查的本质是缩小范围,不是堆工具。 从 cgroup 到进程、到系统调用、到调用栈,每一步都在排除一大片可能性。
  2. eBPF 最大的价值是"无侵入"。 不重启、不改代码、不加 agent,生产环境上敢动手,这点比炫酷的火焰图重要得多。
  3. 别迷信单一指标。 RSS、mmap、page fault、memleak 互相印证,才不容易冤枉好人。
  4. "泄漏"和"涨"不是一回事。 缓存、碎片、延迟释放都会让曲线好看不到哪去,分清楚再动手。

最后说一句,工具永远是第二位的。真正值钱的是你面对一条诡异曲线时,脑子里那套"先问是什么涨、再问谁要的、最后问谁没还"的排查顺序。把这个顺序练熟了,换成别的工具也一样好使。

我是 Echo_Wish,下次再聊。

目录
相关文章
|
6天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
2971 24
|
1天前
|
云安全 人工智能 安全
|
6天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
7天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1297 5
|
云安全 安全 网络安全
|
7天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
20天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3429 52
|
12天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。

热门文章

最新文章