本文导读:本文是系列第 12 篇。Java应用响应变慢、吞吐量下降,根因可能在CPU、内存、磁盘IO、网络任何一个维度。本文系统讲解vmstat/iostat/sar等性能监控工具,深入解析Linux内存管理机制,并结合JVM OOM问题的Linux侧排查思路,以及AI推理场景的GPU/CPU协同瓶颈分析。
关键词:Linux性能监控、Linux性能分析工具、vmstat iostat教程、Linux内存机制、JVM OOM排查、GPU监控nvidia-smi
目录
-
- 一、性能问题排查的系统化思维
- 二、vmstat:系统资源的全局快照
- [三、CPU 性能分析:load average 与 us/sy 占比](#三、CPU 性能分析:load average 与 us/sy 占比)
-
- [3.1 正确理解 load average](#3.1 正确理解 load average)
- [3.2 排查具体是哪个进程占用CPU](#3.2 排查具体是哪个进程占用CPU)
- [四、内存性能分析:理解 Linux 的内存管理哲学](#四、内存性能分析:理解 Linux 的内存管理哲学)
-
- [4.1 free 命令的正确解读](#4.1 free 命令的正确解读)
- [4.2 排查具体是哪个进程占用大量内存](#4.2 排查具体是哪个进程占用大量内存)
- [4.3 Swap 与性能的关系](#4.3 Swap 与性能的关系)
- [五、磁盘 IO 性能分析:iostat 与 iotop](#五、磁盘 IO 性能分析:iostat 与 iotop)
-
- [5.1 iostat:磁盘IO的整体视图](#5.1 iostat:磁盘IO的整体视图)
- [5.2 iotop:精确定位是哪个进程在大量读写磁盘](#5.2 iotop:精确定位是哪个进程在大量读写磁盘)
- [六、AI 推理场景:GPU 与 CPU 协同瓶颈分析](#六、AI 推理场景:GPU 与 CPU 协同瓶颈分析)
- [七、综合实战:JVM OOM 问题的 Linux 侧分析思路](#七、综合实战:JVM OOM 问题的 Linux 侧分析思路)
- 八、常见问题解答(FAQ)
-
- [❓ Q1:vmstat、iostat这些工具系统默认自带吗?](#❓ Q1:vmstat、iostat这些工具系统默认自带吗?)
- [❓ Q2:load average 持续偏高,但CPU使用率(us+sy)并不高,是什么情况?](#❓ Q2:load average 持续偏高,但CPU使用率(us+sy)并不高,是什么情况?)
- [❓ Q3:怎么判断内存确实不够用了,需要给服务器加内存?](#❓ Q3:怎么判断内存确实不够用了,需要给服务器加内存?)
- [❓ Q4:性能监控应该怎么做到长期、持续,而不是出问题了才临时排查?](#❓ Q4:性能监控应该怎么做到长期、持续,而不是出问题了才临时排查?)
- [❓ Q5:AI推理服务GPU利用率很高(接近100%),是不是说明性能已经达到极限了?](#❓ Q5:AI推理服务GPU利用率很高(接近100%),是不是说明性能已经达到极限了?)
- 本篇小结与系列导航
-
- [📚 参考资料](#📚 参考资料)
一、性能问题排查的系统化思维
生产环境出现"系统变慢"的报警时,最容易犯的错误是凭直觉随便猜一个方向就开始排查,结果浪费大量时间却没找到根因。更高效的方式是按照CPU、内存、磁盘IO、网络这四个维度系统化地逐一排查,用数据说话,而不是凭经验臆测。
bash
性能问题排查的标准维度:
CPU瓶颈? 内存瓶颈? 磁盘IO瓶颈? 网络瓶颈?
│ │ │ │
top/vmstat free/vmstat iostat/iotop ss/iftop
│ │ │ │
load average高 swap使用率高 %util接近100% 带宽打满/丢包
us+sy占比高 available低 await时间长 连接数异常
本篇会逐一讲解每个维度对应的诊断工具,并说明各项指标该如何解读,这是排查复杂性能问题的方法论基础。
二、vmstat:系统资源的全局快照
vmstat(virtual memory statistics)是性能排查的第一个命令,能在一屏内同时看到CPU、内存、IO、进程数量的概况,是建立"全局印象"的最快方式。
bash
# 基本用法:第一个参数是刷新间隔(秒),第二个参数是刷新次数
vmstat 2 5
# 含义:每2秒刷新一次,总共刷新5次
# 输出示例:
# 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 0 512000 20000 4000000 0 0 5 12 100 200 25 5 68 2 0
每个字段都对应特定的排查方向,理解它们的含义是用好vmstat的关键:
procs区域的r表示正在运行或等待运行的进程数(接近或超过CPU核心数说明CPU紧张),b表示处于不可中断睡眠状态的进程数(前面第07篇提到的D状态,通常指向IO等待)。memory区域的free是空闲内存,buff和cache是被用作缓存的内存(不是"被占用浪费",需要时会自动释放,第03节会详细解释这个常见误区)。swap区域的si/so分别是从swap换入/换出的速率,如果这两个数字持续非零,说明物理内存不够用,系统在用磁盘空间模拟内存,性能会受到严重影响。cpu区域的us(用户态)、sy(系统态)、id(空闲)、wa(IO等待)四项加起来是100%,wa数值高说明CPU大量时间在等待磁盘IO完成而不是真正在计算。
💡 生产提示 :
vmstat输出的第一行数据是系统启动以来的平均值,实际排查时应该忽略第一行,只看从第二行开始的实时数据,这是新手容易忽略的细节,第一行数字往往和当前真实状态相差很大,容易造成误判。
三、CPU 性能分析:load average 与 us/sy 占比
3.1 正确理解 load average
第07篇已经提到过load average不等于CPU使用率,这里结合性能排查场景深入展开。
bash
uptime
# 输出:15:30:01 up 23 days, load average: 4.50, 3.20, 2.10
# 三个数字分别是最近1分钟、5分钟、15分钟的平均负载
# 配合查看CPU核心数,才能判断load average是否真的过高
nproc
判断load average是否健康的标准公式是:理想情况下load average应该不超过CPU核心数。如果一台4核服务器的load average长期维持在8以上,说明系统持续过载,有大量进程在排队等待CPU资源(或者像前面提到的,在等待磁盘IO,处于D状态)。
bash
# 用 mpstat 查看每个CPU核心的独立使用率(有助于发现"单核打满但其他核心空闲"这类不均衡问题)
sudo apt install -y sysstat
mpstat -P ALL 2 5
⚠️ 踩坑记录 :Java应用经常会遇到"load average很高但应用整体CPU使用率(
top看到的百分比)不高"的反常现象,这种情况要特别警惕------很可能是单线程的GC(垃圾回收)任务把单个CPU核心打满,但其他核心处于空闲状态 ,导致从整体平均值看CPU占用不算特别夸张,但实际上某个关键线程的处理能力已经被严重制约。用mpstat -P ALL查看每个核心的独立使用率,如果发现某一个核心长期100%而其他核心空闲,结合JVM的GC日志分析,往往能定位到是垃圾回收策略配置不合理(比如该用并行GC的场景用了串行GC),这是仅看整体CPU使用率容易遗漏的细节问题。
3.2 排查具体是哪个进程占用CPU
bash
# top命令默认就是按CPU使用率排序,直接观察即可
top
# 进一步定位到具体是Java进程内的哪个线程占用CPU过高
top -H -p <Java进程PID>
# 找到具体线程ID后,转换成16进制(Java线程dump中线程ID是16进制表示)
printf "%x\n" <线程ID>
# 用jstack抓取该Java进程的线程堆栈,搜索刚才转换出的16进制线程ID
jstack <Java进程PID> | grep -A 30 "<16进制线程ID>"
# 这样就能精确定位到是代码里的哪个方法在持续占用CPU,是Java性能问题排查的经典手法
四、内存性能分析:理解 Linux 的内存管理哲学
4.1 free 命令的正确解读
bash
free -h
# total used free shared buff/cache available
# Mem: 15Gi 4.2Gi 512Mi 200Mi 10Gi 10Gi
# Swap: 4.0Gi 0B 4.0Gi
前面第01篇已经初步提到过这个概念,这里结合性能排查场景再深入一层:Linux的内存管理哲学是"空闲内存就是浪费的内存"------系统会主动把暂时没有被应用占用的内存用作磁盘缓存(buff/cache),这样下次读取相同文件时可以直接从内存返回,大幅提升IO性能。当应用真正需要更多内存时,内核会自动从buff/cache中回收一部分给应用使用,这个回收过程通常很快,几乎不影响应用性能。
真正判断内存是否紧张,应该看available这一列,而不是free列 。available是综合考虑了"可以被回收的cache"之后,真正能立即提供给新进程使用的内存估算值,这是更接近实际情况的指标。
⚠️ 踩坑记录 :很多Java团队的运维新手看到
free列数值很小就紧张地认为"内存不够了",盲目重启服务"释放内存",这其实是一种误解性的操作------buff/cache占用的内存本来就是设计为"按需可回收"的,重启服务清空缓存反而会导致后续的文件读取性能下降(因为缓存被清空了,需要重新从磁盘读取),是典型的"不了解原理导致的无效甚至有害操作"。只有当available列的数值持续走低、且系统出现明显的swap使用(si/so非零)时,才说明内存是真正紧张了,这才是需要认真排查和处理的信号。
4.2 排查具体是哪个进程占用大量内存
bash
# 按内存使用率排序,找出最耗内存的进程
ps aux --sort=-%mem | head -10
# 对于Java进程,用jmap查看堆内存使用详情(区分新生代、老年代等具体分布)
jmap -heap <Java进程PID>
# 查看堆内存中对象的分布情况,定位内存占用大户(注意:这个命令会暂停JVM,生产环境慎用,或选择业务低峰期执行)
jmap -histo <Java进程PID> | head -20
4.3 Swap 与性能的关系
bash
# 查看swap使用情况
swapon --show
free -h
# 查看swappiness参数(控制系统使用swap的积极程度,取值0-100)
cat /proc/sys/vm/swappiness
# 默认通常是60,数值越高系统越倾向于提前使用swap
# 对于数据库、Redis这类对延迟敏感的应用所在的服务器,通常建议调低swappiness
# 让系统更倾向于保留物理内存给这些关键应用,而不是过早使用慢得多的磁盘swap
sudo sysctl vm.swappiness=10
# 永久生效(写入配置文件)
echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
💡 生产提示 :swap本质是用磁盘空间模拟内存的应急机制,访问速度比真实内存慢几个数量级。对于MySQL、Redis这类性能敏感型应用所在的服务器,一旦开始大量使用swap,性能会出现断崖式下降,远比"内存稍微紧张一点"更糟糕。生产环境的数据库服务器,往往建议把
vm.swappiness调低(比如10或更低),让系统更倾向于通过回收文件缓存而不是使用swap来释放内存压力,这是一项简单但效果明显的性能调优手段,第28篇内核参数调优会有更系统的讲解。
五、磁盘 IO 性能分析:iostat 与 iotop
5.1 iostat:磁盘IO的整体视图
bash
sudo apt install -y sysstat
# 查看磁盘IO统计(-x 显示扩展统计信息,更详细)
iostat -x 2 5
# 输出示例(节选关键字段):
# Device r/s w/s rkB/s wkB/s await %util
# sda 5.2 45.3 120.5 2300.8 12.3 65.5
%util是判断磁盘是否成为瓶颈的核心指标------表示这块磁盘在采样周期内处于忙碌(正在处理IO请求)状态的时间百分比,接近或达到100%说明磁盘IO已经成为系统瓶颈 ,这块磁盘几乎没有空闲时间来处理新的请求了。await是IO请求的平均等待时间(毫秒),数值越大说明磁盘响应越慢,结合应用的实际延迟感知(比如数据库慢查询)能帮助确认问题是否真的出在磁盘层面。
⚠️ 踩坑记录 :对于使用RAID或者云服务器的虚拟化存储(比如阿里云的ESSD、腾讯云的云硬盘),单看
%util接近100%不一定真的代表性能瓶颈------这类存储设备往往支持更高的并发处理能力,传统单盘场景下"100%忙碌=瓶颈"的判断逻辑在多块盘组成的存储阵列或云盘场景下不完全适用,更准确的判断应该结合await实际等待时间和云厂商控制台提供的IOPS、吞吐量监控指标综合分析,不能只依赖iostat这一个工具的单一指标下结论。
5.2 iotop:精确定位是哪个进程在大量读写磁盘
bash
sudo apt install -y iotop
# 实时查看各进程的磁盘IO占用情况(类似top,但聚焦IO维度)
sudo iotop
# 只显示真正有IO活动的进程(过滤掉IO占用为0的进程,减少噪音)
sudo iotop -o
# 累计模式:显示从iotop启动以来各进程的累计IO量(而不是瞬时速率)
sudo iotop -a
iotop对于排查"磁盘IO很高但不知道是哪个具体进程导致"的问题极其有效,比如某个失控的日志写入逻辑、数据库的慢查询导致大量临时文件读写、或者备份脚本在业务高峰期意外触发,都能通过iotop直接定位到具体的进程和PID,再结合前面学到的工具做进一步分析。
六、AI 推理场景:GPU 与 CPU 协同瓶颈分析
AI大模型推理服务的性能瓶颈往往不局限于GPU本身,CPU、内存、磁盘IO都可能成为制约因素,这是系列融合AI运维主题的重点内容。
bash
# 查看GPU使用情况(NVIDIA显卡,需要先安装好驱动,第23篇会详细讲)
nvidia-smi
# 输出关键信息解读:
# GPU-Util: GPU计算单元的利用率百分比
# Memory-Usage: 显存使用情况(如 8500MiB / 24576MiB)
# Temp: GPU温度(持续高温可能触发降频保护,影响性能)
# 持续监控GPU状态(类似top的实时刷新效果)
watch -n 1 nvidia-smi
# 更详细的GPU查询模式,可以指定需要的具体字段,便于脚本化采集
nvidia-smi --query-gpu=timestamp,utilization.gpu,memory.used,memory.total,temperature.gpu --format=csv -l 1
bash
# 实战场景:AI推理服务响应变慢,排查到底是GPU瓶颈还是CPU/IO瓶颈
# 第一步:观察GPU利用率,如果长期接近100%,瓶颈大概率在GPU计算本身
nvidia-smi --query-gpu=utilization.gpu --format=csv -l 1
# 第二步:如果GPU利用率不高(比如只有30-50%),但推理依然很慢
# 很可能是CPU预处理(如tokenization分词)或者数据加载IO拖慢了整体流程
# 这时候应该转向用前面讲的mpstat、iostat排查CPU和IO维度
top -p $(pgrep -f "vllm\|ollama" | head -1)
💡 生产提示 :AI推理性能优化中一个常见的认知误区是"既然是AI计算,瓶颈肯定在GPU",但实际生产环境中,GPU利用率不高但推理依然慢 的情况并不少见,根因往往在于数据预处理阶段的CPU计算(比如复杂的文本tokenization、图像预处理)或者模型文件、KV缓存的磁盘/内存IO速度跟不上GPU的计算速度,导致GPU"空闲等待数据"。这种场景下盲目升级GPU硬件配置并不能解决问题,反而应该用本篇讲的
mpstat、iostat先确认瓶颈到底在哪个环节,这是性能优化中"先诊断、后开药方"原则的具体体现,第25篇AI推理性能调优会有更深入的讲解。
七、综合实战:JVM OOM 问题的 Linux 侧分析思路
Java应用出现OutOfMemoryError,很多人第一反应是去翻Java代码找内存泄漏,但实际上很多OOM问题的根因或加重因素在操作系统层面,结合本篇所学的工具,给出一套排查思路:
bash
# 第一步:确认是JVM堆内存OOM还是操作系统OOM Killer杀死了进程(这是两种完全不同的现象)
# 检查系统日志,看进程是否被内核的OOM Killer强制终止
dmesg | grep -i "killed process"
journalctl -k | grep -i "out of memory"
# 如果看到类似 "Out of memory: Killed process 12345 (java)" 的日志
# 说明是操作系统层面内存不足,强制杀死了Java进程,这和JVM自己抛出的OutOfMemoryError是不同的问题
# 第二步:如果确认是系统级OOM Killer所为,检查物理内存总量与JVM堆大小配置是否匹配
free -h
ps -ef | grep java | grep -oP '\-Xmx\S+'
# 常见根因:服务器物理内存是8G,但JVM配置了-Xmx6g,加上其他常驻服务和操作系统本身的内存占用
# 实际所需总内存可能超过物理内存上限,导致操作系统在内存紧张时选择杀死内存占用最大的Java进程
# 第三步:查看OOM Killer的评分机制,确认为什么偏偏选中了Java进程(而不是其他进程)
cat /proc/<PID>/oom_score
# oom_score 越高,在系统内存紧张时越容易被优先选中杀死,Java进程因为内存占用通常较大,往往是高危目标
⚠️ 踩坑记录 :很多团队在排查生产Java应用"莫名其妙挂掉"的问题时,只盯着应用自己的日志看,却忽略了检查系统日志(
dmesg/journalctl -k),结果在Java应用日志里完全找不到任何异常堆栈(因为进程是被操作系统内核直接杀死的,根本没有机会打印任何Java层面的异常信息),排查陷入死胡同。这是一个重要的排查习惯提醒:当Java应用进程"无声无息消失"且应用日志没有任何异常记录时,第一时间应该检查系统级别的OOM Killer日志,这往往能立刻揭示真相,而不是在应用代码里大海捞针式地寻找一个根本不存在的"代码bug"。
八、常见问题解答(FAQ)
❓ Q1:vmstat、iostat这些工具系统默认自带吗?
vmstat通常是Linux系统默认自带的基础工具;但iostat、mpstat属于sysstat软件包,很多精简版镜像(特别是云服务器的最小化安装镜像)默认不包含,需要手动apt install sysstat或dnf install sysstat安装。建议在服务器初始化阶段(结合第01篇提到的"必做操作清单")就把这些常用监控工具一并装好,避免出问题时才发现工具缺失,还要先联网安装耽误排查时间。
❓ Q2:load average 持续偏高,但CPU使用率(us+sy)并不高,是什么情况?
这种组合通常指向IO等待(wa占比高)或者大量进程处于不可中断睡眠状态(D状态),而不是真正的CPU计算密集型瓶颈。需要结合vmstat观察wa列、iostat观察磁盘%util和await,大概率能定位到磁盘IO层面的问题,而不是误判为需要升级CPU配置。
❓ Q3:怎么判断内存确实不够用了,需要给服务器加内存?
不能只看free列数值小就下结论(前面已经反复强调这是常见误区)。更可靠的判断依据是:available列持续偏低且接近0、swap的si/so持续非零(说明物理内存真的不够,系统在频繁使用慢速的磁盘swap)、以及应用本身因为内存不足出现频繁GC(Java应用)或者OOM Killer日志(系统级别)。这几个信号同时出现,才是真正需要考虑硬件升级的强信号,而不是单一指标的孤立判断。
❓ Q4:性能监控应该怎么做到长期、持续,而不是出问题了才临时排查?
本篇讲的工具更适合"事后排查"和"实时诊断",要做到长期、持续、可回溯的性能监控,需要搭建专门的监控系统(Prometheus采集指标+Grafana可视化展示),能保留历史数据、设置告警阈值,在问题真正影响用户之前就提前发现趋势异常。第27篇会专门讲解Prometheus+Grafana全栈监控体系的搭建,本篇的工具知识是理解那些监控指标背后含义的基础。
❓ Q5:AI推理服务GPU利用率很高(接近100%),是不是说明性能已经达到极限了?
GPU利用率高确实说明GPU计算单元在持续工作,但不完全等同于"性能已经达到硬件物理极限"------还要结合显存使用率(如果显存有富余,可能可以通过增大batch size提升整体吞吐量)、是否存在多请求排队等待(说明并发处理能力可能是瓶颈,而不是单次计算速度)等更细致的指标综合判断。这部分内容涉及更专业的AI推理性能调优技巧,第25篇会有专门的深入讲解。
本篇小结与系列导航
📌 核心结论 :性能问题排查应遵循CPU、内存、磁盘IO、网络四维度系统化方法论,避免凭直觉盲目猜测。
vmstat提供全局快照,load average需要结合CPU核心数判断,理解Linux"buff/cache是可回收资源而非浪费"的内存管理哲学是避免误判的关键,available而非free才是判断内存压力的准确指标。iostat的%util和await是磁盘IO瓶颈的核心判断依据,Java应用的OOM问题需要区分JVM堆OOM和系统级OOM Killer两种完全不同的场景,后者必须通过dmesg/journalctl -k才能发现根因。AI推理性能瓶颈不应想当然地归咎于GPU,需要结合CPU、IO维度综合诊断。
📚 参考资料
- sysstat 工具集官方文档
- Linux 内存管理官方文档 - kernel.org
- Brendan Gregg 性能分析方法论 - USE Method
- NVIDIA System Management Interface 官方文档
如果本文对你有帮助,请点赞 👍 收藏 ⭐ 支持一下!欢迎在评论区留言交流。
系列标签 :Linux 性能监控 vmstat iostat 内存管理 JVM GPU监控 Java性能调优