尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux内存分析实战:free、vmstat、sar三工具排查压测内存瓶颈

Linux内存分析实战:free、vmstat、sar三工具排查压测内存瓶颈 接手压测任务不到一个月的新人最容易在内存指标上栽跟头线上压到一半打开终端敲了个free -h看到 used 占了 96%心里一紧——内存是不是爆了于是开始怀疑服务配置、怀疑 JVM 参数、怀疑负载均衡折腾一整天最后老同事过来瞥一眼说了一句“你看 available 不就完了吗”。这句轻描淡写的点拨背后其实是 Linux 内存模型和性能分析思维之间的巨大沟壑。性能测试里的内存分析从来不是“内存还剩多少”这么简单。free 告诉你的是当前快照vmstat 告诉你的是动态变化sar 告诉你的是长周期趋势。这三兄弟各管一段组合起来才能还原一台服务器在压测过程中的真实内存状态是正常复用还是真的短缺是缓存波动还是内存泄漏是 swap 抖动还是回收压力导致的延迟毛刺这篇文章就把这三个工具的字段、语义、误区和实操组合一次性讲透让以后再看到“内存告警”四个字你的第一反应不再是被吓到而是冷静地反问一句你指的是哪个指标1. 先把内存分析这件事的底层逻辑理清楚1.1 性能测试里为什么内存分析最容易骗人先说一个最反直觉的事实Linux 操作系统的设计哲学就是“内存别闲着”。你机器上有 16GB 内存应用程序只用掉 4GB剩下的 12GB 如果空着那就是巨大的浪费。于是内核会把这部分空闲内存拿去当 page cache页缓存用来缓存硬盘上读过的文件。如果下次再读同一个文件直接从内存命中速度能比读磁盘快几个数量级。这就导致一个很迷惑的现象压测过程中你打开free -h看到 used 那一列几乎占满了内存但实际上这可能恰恰是系统在高效工作的表现——文件缓存把内存“吃”满了但应用本身一点不缺内存。如果你只看 used 就断定“内存不足”那你大概率会把大量时间浪费在排查一个根本不存在的问题上。我见过太多压测报告里有这种误判“并发到 500 时服务器内存使用率 95%判定存在内存瓶颈”。但实际上 available 还有 20% 以上page cache 占了大量“used”系统只是把内存用在了刀刃上根本没有内存压力。所以内存分析的第一课不是学会看工具而是学会分辨哪些内存是被“缓存”占用的哪些内存是真正被业务逻辑占用的哪些内存是内核正在“着急回收”的。1.2 三个工具的分工快照、流式、趋势free、vmstat、sar 这三个工具虽然都涉及内存但观察维度完全不同。free是快照型工具敲一次输出当前这一瞬间的内存分配情况。适合快速确认“现在怎么了”但不适合观察“趋势如何”。vmstat是流式工具指定间隔持续输出不仅能看到内存变化还能同时看到 CPU、IO、swap 换入换出。适合压测进行中动态观察系统是否出现资源竞争。sar是统计型工具来自 sysstat 包可以把每一秒的数据落盘压测结束后再回放、导出、画趋势图。它最大的价值不在于实时看数而在于“事后复盘”时还原整场压测的内存曲线。用一句话总结free 负责“现场”vmstat 负责“直播”sar 负责“录像”。三者的核心价值不是单个指标有多准而是把内存分析从“看孤立的数字”升级成“看相互印证的时间序列”。1.3 关键认知available 才是给应用的真实余量很多从 Windows 转过来的测试同学习惯性把“剩余内存”当成可用内存。但在 Linux 下free命令输出的剩余内存和你理解的“还能用多少”不是一回事。free 命令里有一列叫 available这一列才是“在不触发 swap 的情况下还能分配给新进程的内存量”。它的估算逻辑大致是free 内存 page cache 中可以回收的部分 一部分 slab 可回收内存但它不是简单的 free buff/cache 相加因为内核要预留一部分内存保证系统稳定运行。内核开发者专门实现了MemAvailable的估算逻辑来回答用户最关心的一个问题“如果我现在再起一个进程内存够不够”所以在性能测试的语境下判断内存是否紧张的优先指标排序应该是available 优先于 freeswap 变化优先于百分比趋势优先于单点。如果 available 持续稳定在总内存的 20% 以上哪怕 free 只剩几百兆都不用太紧张反过来如果 available 持续下降且伴随 swap 上升那才是真正的危险信号。2. free 命令把每一列的意思都嚼碎了说2.1 一次 free -h 输出逐字段解读先跑一下free -h看看典型输出$ free -h total used free shared buff/cache available Mem: 7.6G 5.2G 356M 112M 2.1G 1.8G Swap: 2.0G 128M 1.9G逐列看total物理内存总量这个没悬念。used已经被使用的内存。注意这里的 used 在不同版本中计算方法不同。老版本procps 3.3.10 之前used total - free - buff/cache新版本 used total - available。所以 debian 老系统和 centos 新系统上的 used 含义差很多跨平台对比时要留个心眼。free完全没被用上的内存包括内核和用户进程都没碰过的空闲页。数值低不代表内存紧张只代表内存已经被系统充分“利用”了。sharedtmpfs 等临时文件系统占用的内存多个进程可以共享比如/dev/shm。压测中跑了一些中间件、消息队列的shared 偶尔会比较高。buff/cachebuffer 和 cache 的合计。简单说buffer 是块设备缓冲cache 是文件页缓存。真实业务里 cache 占大头压测中如果一个接口反复读同样的静态文件cache 会非常可观。available估算出的“可分配给新进程”的内存这才是我们做性能测试时最该盯的值。再补一个容易混淆的点free命令还有一个-w参数可以把 buff/cache 拆开显示成独立的buffers和cache两列。压测中发现缓存异常增长时建议用free -w -h区分是块设备缓冲还是文件缓存定位方向会清晰很多。2.2 判断内存健康的三种典型形态我在压测观察 free 输出时一般只看三种形态第一种available 稳定且占总内存 20% 以上buff/cache 有波动但不大。这种最常见说明内存处于健康状态。即使 free 只有几百 MB也不需要干预。第二种available 持续下降而且下降的同时 cache 也在掉。这说明系统正在回收页缓存来满足不断增长的内存申请。如果 available 一路跌破 10%说明系统很快要进入 swap 压力区。第三种free 和 available 双低swap used 开始增长。这就很危险了说明内存真的不够用了内核已经有部分内存页被换到磁盘。这种情况下压测的响应时间大概率已经出现明显劣化这是典型的“内存瓶颈”不是简单的缓存波动。给新手一个可执行的口诀先看 available再看 swap最后才看 used。如果 available 没崩used 再高都不用慌。2.3 压测现场怎么用 free 记录数据压测过程中单敲一次 free 意义不大因为内存状态每秒钟都在变。我习惯用持续采样模式free -h -s 5这条命令每 5 秒刷新一次输出可以一直挂着配合终端工具script或者直接重定向到文件压测结束后就有了一条完整的内存曲线。不过 free 的输出不带时间戳建议用 watch 加时间戳的方式watch -n 5 date %H:%M:%S; free -h这样每 5 秒打印一次当前时间和完整 free 输出事后整理数据时能直接对齐 jmeter 的聚合报告。如果你觉得 watch 的输出格式太乱也可以用一行循环for i in $(seq 1 120); do date %H:%M:%S; free -h | grep Mem:; sleep 5; done这些都是我压测现场的“老手艺”不花哨但胜在稳定可靠而且任何一台服务器都能跑不依赖额外的 agent 工具。3. vmstat从内存到整机性能的动态视角3.1 一行 vmstat 输出到底说了什么free 能告诉我们内存“现在有多少”但回答不了“内存变化的节奏是怎样的”。这个活要交给 vmstat。跑一个采样$ vmstat 2 10 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 128M 356M 20M 2.0G 0 0 40 60 1200 2500 30 15 55 2 0 3 0 128M 340M 20M 2.0G 0 0 50 70 1300 2600 32 17 50 1 0对内存分析来说重点关注这几个列swpd已经使用的 swap 空间单位是 KB。如果这个数持续增长说明物理内存已经不够用系统正在把内存页往磁盘上倒腾。si 和 so每秒从 swap 换入和换出的数据量。这两个列是内存压力的“第一信号”。正常情况下它们应该长期为 0一旦跑起来说明系统已经开始频繁地在内存和磁盘之间搬运数据。free、buff、cache和 free 命令对应但 vmstat 的优势在于能看到这些值随时间的波动曲线。r运行队列长度也就是多少个进程在等待 CPU。r 值高通常说明 CPU 紧张但如果内存回收线程也在抢 CPU这个值同样会涨。us、sy用户态和内核态 CPU 占比。内存回收和 swap 相关的操作都属于系统态如果 sy 持续偏高需要警惕是否和内存压力有关。3.2 压测中怎么用 vmstat 盯内存变化压测进行中我一般这样启动 vmstatvmstat 2 300每 2 秒打一条连续打 300 条也就是覆盖 10 分钟的场景。这样既能看清细粒度波动又不会让终端刷到看不清前面的数据。实际操作时我会把压测过程切成三段观察窗口压测初期03 分钟重点看 free 是否快速下降、cache 是否快速上升。此时内存从“低负载”切到“高负载”会发生大量文件缓存填充。如果 free 掉了 2GB 但 cache 涨了 2GB说明这是缓存填充而非业务内存消耗不用紧张。压测中期1015 分钟重点看 si/so 是否出现非零值r 是否持续走高sy 是否异常。如果 si/so 开始频繁跳变即使系统吞吐还没掉也要做好响应时间即将劣化的准备。压测后期即将结束前重点看 swpd 是否还在增长。如果 swpd 在压测后段才快速上升说明这个并发量级正好踩在内存临界点上。下次压测可以把并发降一档看看 swpd 是否能回到零。3.3 vmstat 的局限它告诉你有问题但不说问题在哪vmstat 最大的毛病是“只看总量看不到是谁”。它告诉你系统内存吃紧但不会告诉你是哪个进程在疯狂吃内存。所以我一向把 vmstat 当成“报警器”一旦 si/so 冒头立刻用 pidstat 精确定位到进程pidstat -r 1 10这条命令每秒输出一次各进程的内存占用变化重点看 RSS常驻内存集列。如果某个进程的 RSS 在压测过程中一路走高、不回落那就是内存泄漏的头号嫌疑人。再配合 top 按内存排序top -o %MEM看前几行有没有超出预期的进程。压测中遇到过最典型的场景是一个缓存组件在内存充裕时不断膨胀等到内存吃紧时又疯狂触发 GC导致应用线程卡顿最终表现为接口响应时间大面积超时。这种问题靠 free 和 vmstat 看不出来必须落到进程维度。4. sar从“快照”到“长周期趋势”4.1 sar -r 内存统计里那些字段的含义说个小插曲很多做遥感、雷达方向的朋友看到“SAR”会先想到合成孔径雷达。但在性能测试圈子里sar 是 Linux 上 sysstat 包提供的 System Activity Reporter跟雷达成像没有半点关系。这两个名字的缩写撞车在团队协作时偶尔会闹出小误会。sar 的精髓在于可以后台落盘把整个压测周期的数据完整保存下来结束后再统一分析。内存相关的最常用命令是sar -r 2 60这条命令每 2 秒采样一次一共采 60 次也就是 2 分钟内的内存使用记录。输出的字段里重点关注这几个kbmemfree、kbmemused空闲和已使用的物理内存单位 KB。%memused已使用内存占总内存的百分比这是很多人写压测报告时最爱的指标。kbbuffers、kbcachedbuffer 和缓存的数量。kbcommit、%commit当前工作负载申请的内存总量占总内存的比例这个指标很多人忽略但它特别能说明问题——它反映的是“所有进程总共向内核承诺会用多少内存”而不是“现在用了多少”。如果 %commit 超过 100%意味着系统已经进入超额分配状态一旦进程真的把内存全用起来就只能依赖 swap 兜底。压测时我盯的是 %commit 而非 %memused。因为 %memused 高可能只是缓存占用而 %commit 持续逼近 100% 才说明真有人在向系统申请大量内存。4.2 sar -B 和 sar -S回收与 swap 的秘密内存分析的深层问题通常不是“内存还有没有”而是“内存够不够的同时系统有没有在花代价回收内存”。回收代价要看sar -Bsar -B 2 60重点字段pgscank/s每秒被后台内核线程 kswapd 扫描的页数。这是温和的内存回收路径系统还有余量。pgscand/s每秒被直接扫描的页数。这是“着急了”的路径说明内存分配等不及后台回收进程开始亲自下场找页。这个值如果持续高企说明内存是真的缺而且响应时间大概率已经劣化。pgfree/s每秒释放的空闲页数量。%vmeff页面回收效率计算公式大约是 (pgsteal)/(pgscan)代表回收页面的成功率。如果这个值反复掉到 10% 以下说明系统拿不到多少可回收的内存页回收效率极差内存危机基本坐实。而 swap 维度的硬数据要看sar -Ssar -S 2 60输出中的 kbswpused 代表 swap 已用量kbswpin/kbswpout 代表每秒换入换出的数据量。和 vmstat 的 si/so 是同一件事但 sar 的优势是能落盘、能回放、能出趋势图。压测中最典型的 swap 特征是这样的场景刚启动时 kbswpused 保持平稳跑到第 20 分钟开始缓慢上升第 40 分钟后加速。这种“前平后陡”的曲线基本可以判定为内存泄漏导致的 swap 累积而非单纯的容量不足。4.3 用 sar 识别压测过程中的内存泄漏sar 的一个核心用法是把数据保存下来压测结束后统一分析sar -r -B -S -o /tmp/mem.sar 2 /dev/null 21 这条命令把内存、内存回收、swap 三组数据同时采集并写入/tmp/mem.sar文件。压测结束后用sadf -d导出成 CSV 格式做进一步分析sadf -d /tmp/mem.sar -- -r mem_r.csv sadf -d /tmp/mem.sar -- -B mem_B.csvCSV 文件可以直接扔进 Excel 或 Grafana 里画曲线。判断是否存在内存泄漏时我的经验是在并发量不变的情况下%memused 或 kbcommit 如果呈持续线性上升趋势并且在压测结束后仍然缓慢爬升、不回落那基本可以确认存在内存泄漏。注意单纯的缓存增长会在压测结束后快速回落而泄漏不会。之前定位一个 Java 服务的堆外内存泄漏就是用 sar 保存了整晚压测的数据第二天把 %memused 曲线拉出来发现即使在 GC 压力极高的情况下内存用量依旧单调上升最终顺着 pidstat 定位到了 direct buffer 的未释放问题。没有 sar 的落盘数据这种渐变式问题很难单靠现场观察发现。5. 一次压测实践三命令组合定位内存瓶颈5.1 场景设计与采集布局说一个真实经历过的案例帮助你把上面三个工具串起来。当时在压测一个文件下载接口服务器配置是 8 核 16GB 内存Jmeter 脚本模拟 300 并发持续请求压测时长 30 分钟。接口本身做了静态文件读取 响应缓存理论上内存压力不大。但压测到第 15 分钟时Jmeter 聚合报告里的响应时间从均值 80ms 突然涨到 600ms我第一反应是怀疑磁盘 IO因为下载接口要读盘。现场采集布局是这样的终端一跑 free 快照监控watch -n 5 date %H:%M:%S; free -h终端二跑 vmstat 动态观察vmstat 2 300终端三跑 sar 落盘留痕sar -r -B -S -o /tmp/download_test.sar 2 /dev/null 21 5.2 数据回放三个阶段的内存变化把三条线汇总起来看整个过程分成了三个阶段。阶段一08 分钟free 从 12GB 快速降到 6GBcache 从 2GB 涨到 7GBavailable 维持在 5GB 左右。这个阶段的特性非常典型——并发请求把文件读进 page cache内存被充分利用但系统毫无压力。阶段二820 分钟cache 涨到了 10GBavailable 跌破 3GBvmstat 里 si/so 开始出现非零值而且 so 大于 si——内存被换出到磁盘的量开始增加。这里我判断不是业务内存不够而是文件缓存把内存吃得太满导致新的内存申请必须依赖内存回收甚至 swap 来满足。阶段三2030 分钟sar -B 里的 pgscand 明显冒尖%vmeff 一度跌到 5% 以下。同时 sy内核态 CPU从 8% 涨到 25%。这说明系统大量 CPU 时间花在了内存回收和 swap 搬运上应用响应时间自然跟着劣化。三个工具给出的信息互相印证free 告诉你“内存变少”vmstat 告诉你“swap 在动”sar 告诉你“回收效率在崩”。最终结论不是服务本身内存不足而是“文件缓存 大量并发读”导致内核不断做低效回收。5.3 定位根因与处置建议确认方向后用 pidstat 定位到具体进程pidstat -r 1 10 -p pid发现某个负责缓存的组件 RSS 在压测期间涨了接近 4GB而且完全没有回落的迹象。再结合 sar 的 kbcommit 变化判定是组件缓存策略过于激进把本来应该留给文件缓存和业务进程的内存抢走了。处置上没有大动干戈调整了组件的缓存上限参数重启后又跑了一轮同样的压测脚本。结果这次 available 始终保持在 5GB 以上pgscand 基本归零响应时间均值稳定在 85ms 左右。整场问题从发现到解决只花了一个下午靠的就是 free、vmstat、sar 三种视角交叉验证而不是拿到一个指标就瞎猜。6. 内存分析常见误判与排查速查表6.1 几个我踩过的坑第一个坑把旧版本的 free 命令 used 当成业务内存使用量。老版本 used 包含了 buff/cache数值上很容易超过 90%。如果拿这个值写进压测报告结论必然失真。建议统一用free -h且关注 available。第二个坑只看 free 不看 si/so。free 只能看到快照swap 抖动这种瞬时现象必须依赖 vmstat 或 sar。某次压测里 free 显示 available 还剩 20%但响应时间已经在劣化后来发现 si/so 正在剧烈跳动内存页在内存和磁盘之间来回搬运这才是真实原因。第三个坑不区分缓存增长和泄漏。page cache 增长是正常的压测结束会释放泄漏增长是不正常的压测结束也不会回到原值。所以判断泄漏必须看“压测结束后的曲线”而不是压测中的瞬间值。6.2 常用内存指标速查表指标判断逻辑正常范围警戒阈值free完全空闲内存无统一标准需结合 cache持续小于 total 的 5% 且 available 同步走低available可分配给新进程的内存量大于 total 的 20%持续低于 10%si/soswap 换入/换出速率长期为 0 或接近 0持续非零且数值超过 1000 块/s%memused内存使用率需区分 cache 占用如果排除 cache 后仍持续攀升警惕泄漏%commit已承诺内存占总内存比小于 100%接近或超过 100%pgscank/s后台回收扫描页数有波动但不大持续高位pgscand/s直接回收扫描页数接近 0持续非零响应时间大概率劣化%vmeff页面回收效率30% 以上反复低于 10%这张表不是放之四海皆准的绝对值但作为压测排查的第一版判断依据是够用的。具体业务、具体版本、具体压测场景下更稳妥的做法是先跑一轮小并发基线把各项指标的“健康基线”记录下来再对比大并发压测时的偏离程度。6.3 一条命令同时采集三个维度最后分享一个常用的压测采集脚本片段把三个工具组合起来一条命令完成多维度采样mkdir -p /tmp/mem_analysis for i in $(seq 1 600); do echo $(date %H:%M:%S) /tmp/mem_analysis/free.log free -h /tmp/mem_analysis/free.log vmstat 1 2 /tmp/mem_analysis/vmstat.log sleep 5 done跑这个循环的同时后台再挂一个 sar 落盘sar -r -B -S -o /tmp/mem_analysis/mem.sar 2 /dev/null 21 压测结束后free.log 负责还原快照细节vmstat.log 负责观察动态变化mem.sar 负责回放长周期趋势。三个文件对同一场压测给出三个角度的证据链写压测报告的时候不用再靠嘴硬直接把数据曲线贴出来结论自然水落石出。在我实际操作中体会最深的一件事内存分析里 90% 的“异常”都是因为只看了单个指标被表层的数字骗了。free 的 used 高可能只是缓存策略聪明si/so 冒头可能是回收时机踩点%memused 陡增可能是压测刚启动的缓存填充。真正的高手不是比谁记得字段多而是比谁能把 free、vmstat、sar 三兄弟的数据放在同一条时间线上互相印证。把这份“交叉验证”的思维练成本能压测中再遇到内存告警你就能保持冷静一步步还原出系统的真实状态。
返回列表