记一次 Linux 内存告警排查:缓存、swap 与 OOM Killer 的取舍
一、告警现场
凌晨,监控报内存使用率 92%,swap 也在涨,业务却还能返回,只是偶发变慢。这时不要先重启:重启会丢掉现场,缓存和连接重建后问题暂时消失,下个高峰还会回来。先固定现场:记下时间,保存 free、top、dmesg 输出,确认是单台还是多台同时告警。单台多半是本机进程或配置问题,多台同时出现,先怀疑批量发布或流量突增。
二、分清已用、缓存与 swap
free -m 的第一行最容易误读。Linux 会把空闲内存拿去做 page cache,这部分在内存紧张时可以回收,不等于业务真的吃掉了内存。真正要看 available 一列:它是内核估算的、不触发 swap 时还能给新进程的内存。available 充裕时,即使 used 很高也不用慌;available 持续走低、swap 同时上涨,才说明系统已在用磁盘换内存。
再看 /proc/meminfo。MemAvailable 是可用内存估算,Active 与 Inactive 区分近期使用过的页,Dirty 是等待回写的数据,Slab 是内核对象缓存。Slab 突然膨胀,常指向句柄或 dentry 泄漏;Dirty 居高不下,要看磁盘写入是否被堵住。把这些数字与业务曲线对齐,比只盯一个百分比可靠。
三、swap 能救急,也会掩盖问题
swap 很贵:匿名页被换出后,下次访问要从磁盘读回,延迟会从毫秒级变成几十毫秒。swappiness 越高,内核越倾向换出不活跃的匿名页;越低,越倾向先回收文件缓存。对延迟敏感的服务,一般调低 swappiness,而不是直接关掉 swap。完全关闭 swap 会让内存耗尽时没有缓冲,OOM 冲击更直接。
用 vmstat 看 si、so:长期大于零说明系统一直在换页,这时应加内存、降并发或修泄漏,而不是扩 swap。把磁盘当内存用,只会把延迟问题放大成雪崩。
四、OOM Killer 杀谁有规则
内存不够又回收不出可用页时,内核触发 OOM Killer,按占用、运行时间、子进程和 oom_score_adj 打分选一个进程杀掉。关键业务若没调过 oom_score_adj,很可能因占用最大而先被杀。dmesg 里能看到 Out of memory 记录和被杀进程。排查先确认被杀的是否在预期之外,再看当时水位。核心进程可适当调低 oom_score_adj,但这只是把风险转嫁给其他进程,必须按业务重要性评估。
五、可复用的排查顺序
先看全局:free -m、top 按内存排序,确认 available、swap、负载是否同步变化。再看进程:ps 按 RSS 排序,找占用前几名;Java 要看堆外内存,Go 要看 Goroutine 与缓存,Python 要看常驻对象与连接。接着看系统:dmesg 找 OOM,meminfo 看 Slab 与 Dirty,vmstat 看换页。最后看业务:最近发布、配置变更、流量曲线、定时任务是否与告警时间重合。
干预要最小:先限流或降级非核心任务,必要时只重启可疑进程并观察曲线是否回落。不要全量重启,更不要同时改多个参数,否则无法确认哪一步起了作用。
六、取舍清单
缓存:page cache 可回收,但频繁回收说明读写量大或内存不足;热点数据应进应用缓存并设上限。swap:保留少量作缓冲,调低 swappiness 保护延迟,把持续换页当作扩容或修泄漏的信号。OOM:给核心进程合理分数,用 cgroup 内存上限把单个服务关进笼子,让它先触顶,而不是拖垮整机;同时把内存上限、并发与连接池当作整体算账。判断泄漏要看 available 是否单调下降、重启后是否再次爬升,也要警惕容器 cgroup 限制:宿主机有内存,容器触顶同样会被杀。
七、结语
排查的核心不是把数字降下来,而是分清这块内存是谁、在干什么、能不能回收。缓存高不一定是病,swap 涨一定是信号,OOM 杀谁一定有规则。把几条线对齐,下一次凌晨告警就不用再凭感觉做取舍了。
- 点赞
- 收藏
- 关注作者
评论(0)