Linux 直接内存回收拖高 P99:用 vmstat、perf 和 NUMA 证据定位

发布时间:2026/8/15 14:18:17
Linux 直接内存回收拖高 P99:用 vmstat、perf 和 NUMA 证据定位 Linux 直接内存回收拖高 P99用 vmstat、perf 和 NUMA 证据定位1. 高并发服务中的 P99 抖动直接内存回收现场诊断Gateway 出现 P99 尖峰时先对齐应用 Trace、GC、数据库等待、vmstat和perf。下面的输出是构造输入目的是说明如何确认直接回收而不是提供一组“正常值”。在排查此类问题时前端与业务层容易误判为数据库锁竞争或应用层垃圾回收GC停顿。如果数据库和 GC 没有同步变化而 Sys CPU、阻塞进程和直接回收指标在同一窗口上升才把内存回收列为重点。具体比例从目标主机采集单个 CPU 数值不能独立证明根因。2. 现场排查用 sar、vmstat 与 perf 锁定内核堆栈为定位 Sys CPU 的高消耗根因需要使用 Linux 系统诊断工具链提取现场证据。首先在延迟抖动发生期间运行vmstat 1观察系统物理内存与页面交换动态procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 3 0 0 185420 12480 3241500 0 0 0 120 18450 32410 42 48 10 0 0 8 2 0 98210 12480 3241800 0 0 0 4500 24510 48920 38 52 10 0 0 -- 产生卡顿 1 0 0 245120 12480 3242100 0 0 0 0 15200 28100 45 5 50 0 0观察数据变化free空闲内存迅速降至 98MB 左右同时b阻塞进程数升至 2sy内核态 CPU 占用率上升至 52%。随后开启perf top深入内核态函数级别的热点捕获# 捕获内核 CPU 热点函数 10 秒 sudo perf top -e cpu-clock -p $(pgrep -f gateway) --min-percent 2采集中捕获到的内核堆栈高频热点函数如下所示Overhead Shared Object Symbol 38.45% [kernel] [k] try_to_free_pages 22.10% [kernel] [k] get_page_from_freelist 14.32% [kernel] [k] _raw_spin_lock_irqsave 8.12% [kernel] [k] shrink_inactive_list根据追踪结果占用系统 CPU 的主要逻辑是 Linux 内核在执行try_to_free_pages——即Direct Reclaim直接内存回收。malloc和mmap不一定立即分配物理页实际分配常在缺页或后续访问时发生。内存紧张时分配路径可能进入 direct reclaim 并阻塞业务线程回收是否涉及页回写取决于页类型和存储状态。是否造成卡顿应通过 PSI、缺页、回收与 I/O 指标共同判断。3. 内核机制拆解内存分配水位与 NUMA 陷阱系统在后台存在kswapd0异步回收进程的情况下仍触发同步 Direct Reclaim 的根源在于 Linux 内核 Buddy System伙伴系统的水位控制机制。Linux 内核将物理内存划分成多个 Zone如 Zone NORMAL、Zone DMA32每个 Zone 维护三条水线WMARK_MIN、WMARK_LOW和WMARK_HIGH。分配路径会先检查各 Zone 的水位和可用页必要时触发回收或回退到其他内存域。此外在多路 CPU 服务器上NUMA 架构下的zone_reclaim_mode配置也是常见隐患。当 NUMA Node 0 内存不足时若sysctl vm.zone_reclaim_mode设置为1内核将优先在 Node 0 本地强行回收 Page Cache而不会跨节点调用 Node 1 的空闲内存从而推高局部回收延迟。4. 优化落地可复现的 Linux 内核内存调优 Shell 脚本明确根因后调优主要包含以下步骤提高异步回收水位线watermark_scale_factor提升kswapd提前响应阈值关闭 NUMA 节点的强行本地回收 (zone_reclaim_mode 0)调整dirty_ratio避免脏页堆积打爆磁盘导致回收阻塞。可使用如下 Shell 脚本固化内核配置#!/bin/bash # Linux 内核内存回收与 P99 延迟专项调优脚手架 set -e echo 开始应用 Linux 内核内存调优参数 # 1. 关闭 NUMA 节点内强行内存回收 (避免本地回收引发的巨大阻塞) sysctl -w vm.zone_reclaim_mode0 # 2. 调大 kswapd 异步回收水线距离 (默认 10设为 200 相当于预留 2% 物理内存缓冲区) sysctl -w vm.watermark_scale_factor200 # 3. 避免内存过度 Overcommit 导致 OOM sysctl -w vm.overcommit_memory1 # 4. 控制脏页回写水线防止大块写脏页卡死文件系统 LRU 扫描 sysctl -w vm.dirty_background_ratio5 sysctl -w vm.dirty_ratio10 # 5. 适度保留目录项与 inode 缓存 (默认 100) sysctl -w vm.vfs_cache_pressure50 # 固化到 /etc/sysctl.d/99-memory-optimization.conf 防止重启失效 cat EOF /etc/sysctl.d/99-memory-optimization.conf vm.zone_reclaim_mode 0 vm.watermark_scale_factor 200 vm.overcommit_memory 1 vm.dirty_background_ratio 5 vm.dirty_ratio 10 vm.vfs_cache_pressure 50 EOF sysctl -p /etc/sysctl.d/99-memory-optimization.conf echo 内存调优参数生效完毕正在检查当前水位状况 cat /proc/zoneinfo | grep -E Node|pages free|min|low|high | head -n 155. 效果验收指标来源与对照条件用目标环境可承受的阶梯负载做对照测试记录参数调整前后的指标性能指标采集来源对照时固定的条件API P99 / P999入口指标、负载工具请求集、到达率、实例资源与工作集Sys CPU 与热点容器指标、perf采样时长、内核版本和后台任务Direct Reclaim/proc/vmstat、tracepoint内存压力、Page Cache 与 NUMA 绑定kswapd 回收与扫描效率vmstat、内核 tracewatermark 候选值和相同负载阶段调参是否减少 Direct Reclaim要比较相同负载下的回收频次、Sys CPU 与延迟分位数。若工作集或流量变化对照结果无效。6. 总结收尾遇到卡顿先查哪里当高并发应用出现卡顿而应用日志没有直接线索时可按以下顺序定位检查vmstat中syCPU 的异常抖动使用perf top确认是否存在try_to_free_pages内核调用核查 NUMAzone_reclaim_mode与内存水位配置。理解 Linux 内核内存回收的水位逻辑能够为解决高并发场景下的随机延迟提供明确的工程路径。