Linux 性能排查
线上机器变慢时,排查的顺序是先看整体资源(CPU、内存、磁盘 I/O、网络)哪一项饱和,再定位到进程,最后定位到进程里的线程或代码。本文讲 load average 的含义、几个常用工具的关键字段,以及“CPU 高”“系统卡”“CPU 不高但接口慢”三类场景的排查路径。具体到 Java 进程的线程和代码定位见 Java CPU 飙高排查。
1. 面试核心
先记住这几条,再读正文- load average 是 1、5、15 分钟内处于可运行(R)和不可中断睡眠(D,通常在等磁盘 I/O)状态的平均进程数,不是 CPU 使用率。要和 CPU 核数比较:持续高于核数说明有任务在排队。卡 · load average
- load 高不一定是 CPU 忙:大量进程在等 I/O 时 load 也会升高,而 CPU 使用率很低。用
top的us/sy/wa和vmstat的r/b区分。 - CPU 使用率高的排查链路:
top找进程 →top -Hp或pidstat -t找线程 →perf top、jstack等找到代码;同时区分用户态(业务计算)和内核态(系统调用、中断、上下文切换)。卡 · 三类场景的排查路径 - CPU 不高但接口慢,瓶颈在等待:磁盘 I/O、网络与下游依赖、锁、连接池或线程池耗尽、内存不足导致的交换。按“机器资源 → 网络 → 应用内部 → 下游”的顺序逐项排除。卡 · 三类场景的排查路径
- 先看趋势再看快照:对比问题前后的监控曲线,确认是突增还是缓慢增长,以及是否与发布、流量变化同时发生。
2. load average
uptime 和 top 第一行显示三个数,分别是 1、5、15 分钟的指数加权平均负载。Linux 的负载统计两类进程:
- R:正在运行或在运行队列中等待 CPU。
- D:不可中断睡眠,通常在等待磁盘 I/O,也可能在等 NFS 或某些内核锁。
判断方法:
| 情况 | 含义 |
|---|---|
| 负载 < 核数 | CPU 有空闲 |
| 负载 ≈ 核数 | CPU 刚好用满 |
| 负载持续 > 核数 | 有任务在排队;再看是 CPU 忙还是 I/O 等待 |
| 1 分钟值远高于 15 分钟值 | 负载正在上升,问题刚发生 |
| 1 分钟值远低于 15 分钟值 | 负载在回落 |
核数用 nproc 或 lscpu 查看。负载高的常见原因:计算密集的进程、大量线程竞争 CPU、磁盘 I/O 慢导致大量 D 状态进程、频繁的上下文切换和中断。
3. 常用工具与关键字段
| 工具 | 看什么 | 关键字段 |
|---|---|---|
top / htop | 整体和进程级 CPU、内存 | us 用户态、sy 内核态、wa 等待 I/O、si 软中断、st 被虚拟化宿主占用;进程的 %CPU、RES、状态 |
vmstat 1 | 运行队列、内存、交换、上下文切换 | r 等待 CPU 的进程数、b 阻塞的进程数、si/so 交换、cs 上下文切换、wa |
free -h | 内存 | 看 available 而不是 free;buff/cache 可回收 |
iostat -x 1 | 每块磁盘的 I/O | r_await/w_await 平均等待时间、aqu-sz 队列长度、%util 忙碌比例 |
pidstat -u/-d/-w 1 | 按进程看 CPU、I/O、上下文切换 | 定位到具体进程 |
iotop | 按进程看实时磁盘读写 | 找出 I/O 最多的进程 |
perf top | 热点函数 | 定位到函数,包括内核函数 |
dmesg | 内核日志 | OOM Killer、磁盘错误 |
iostat 按磁盘统计,用于判断哪块盘有压力;iotop 按进程统计,用于找出是谁在读写。%util 接近 100% 对单块机械盘意味着饱和,但 SSD 和 RAID 可以并行处理请求,%util 高不一定饱和,要结合 await 判断。
4. 三类场景的排查路径
CPU 使用率高
top按 CPU 排序找到进程,看us和sy的比例。us高:业务计算多。top -Hp <pid>找到最忙的线程,用perf top -p <pid>或语言自带工具(Java 用jstack,把线程 ID 转成十六进制后在线程栈中查找)定位代码。常见原因有死循环、正则回溯、序列化大对象、频繁 GC。sy高:系统调用、上下文切换或中断过多。用vmstat看cs,pidstat -w找切换多的进程,strace -c -p <pid>统计系统调用。常见原因有线程过多、锁竞争、小块读写。si高:软中断,通常是网络包量大。
系统卡、内存和 CPU 都高
free看available是否很低,vmstat的si/so是否持续不为零。发生交换时,进程访问内存要等磁盘,整体变慢。- 按内存排序找到占用最多的进程,判断是正常增长(缓存)还是泄漏(持续上涨不回落)。
dmesg | grep -i oom检查是否有进程被 OOM Killer 杀掉。- 内存紧张时 GC 也会更频繁,CPU 随之升高,要确认因果顺序。
CPU 不高但接口慢
- I/O:
vmstat的wa和b是否高,iostat的await是否升高,iotop找出读写多的进程(日志、备份、数据库)。 - 网络:到下游的延迟和丢包(
ping、mtr),连接状态是否异常(ss -s),DNS 解析是否慢。 - 应用内部:线程池、连接池是否耗尽,是否在等锁;线程栈中大量线程处于等待状态说明在等资源。
- 下游依赖:数据库慢查询、缓存失效、第三方接口变慢。用链路追踪看耗时在哪一段,见日志、指标与追踪。
5 · 面试题卡片
5.1 top 显示的 load average 三个数字是什么含义?怎样判断 CPU 处于高负载?负载高可能有哪些原因?
出现公司:京东、百度、触宝、字节跳动
考察重点
- 负载统计的是 R 和 D 状态的进程数,不是使用率。
- 与核数比较的判断方法;区分 CPU 忙和 I/O 等待。
相关内容:load average、常用工具与关键字段。
参考回答
三个数是最近 1、5、15 分钟的平均负载,按指数加权计算。Linux 统计的是处于可运行状态(正在运行或等待 CPU)和不可中断睡眠状态(通常在等磁盘 I/O)的进程数,所以它表示排队的程度,不是 CPU 使用率。
判断时和核数比较:负载持续高于核数,说明有任务在排队;1 分钟值远高于 15 分钟值,说明负载正在上升。负载高之后还要区分原因:top 中 us、sy 高是 CPU 忙,可能是计算密集、线程过多竞争、频繁上下文切换;wa 高、vmstat 中 b 列大,是大量进程在等 I/O,CPU 使用率可能并不高。负载过高的后果是请求排队,响应时间变长,严重时健康检查超时、服务被摘除。
5.2 发现某台机器 CPU 使用率很高、系统很卡,你怎样排查?
出现公司:虾皮、哔哩哔哩、持安科技
考察重点
- 从机器到进程、线程、代码的定位链路。
- 区分用户态与内核态;内存不足引起的交换与 OOM。
相关内容:三类场景的排查路径、Java CPU 飙高排查。
参考回答
先看监控确认开始时间,是否和发布、流量突增同时发生。登录机器后用 top 按 CPU 排序找到进程,看 us 和 sy 的比例。us 高是业务计算,用 top -Hp <pid> 找到最忙的线程,再用 perf top 或语言工具定位代码,Java 进程把线程 ID 转成十六进制后在 jstack 输出中找对应栈,常见原因是死循环、正则回溯、大对象序列化和频繁 GC。sy 高是系统调用或上下文切换多,用 vmstat 看 cs、pidstat -w 找切换多的进程,strace -c 统计系统调用。
如果内存也高,用 free 看 available,vmstat 看 si/so:发生交换时所有访问都会变慢;dmesg 检查 OOM Killer 记录;按内存排序找到进程,判断是缓存增长还是泄漏。止血可以先摘流量、扩容或重启,但要先保留线程栈、堆转储等现场。
5.3 一台 Linux 服务器 CPU 占用不高,但接口访问很慢,你会怎样排查?
出现公司:共济科技、美团、字节跳动、杭州观远数据
考察重点
- CPU 不高说明在等待:I/O、网络、锁、池耗尽、下游。
iostat与iotop的分工;按层次排除。
参考回答
CPU 不高而响应慢,说明请求大部分时间在等待,要找出在等什么。先看机器:vmstat 的 wa 和 b 列是否高,iostat -x 看哪块盘的 await 和队列长度升高,再用 iotop 或 pidstat -d 找出读写最多的进程,例如日志刷盘、备份任务;free 确认没有发生交换。
然后看网络:到下游的延迟和丢包,ss -s 看连接数和异常状态,DNS 解析是否变慢。再看应用内部:线程池或连接池是否耗尽,线程栈中是否有大量线程在等锁或等连接。最后看下游依赖:数据库慢查询、缓存命中率下降、第三方接口变慢。用链路追踪可以直接看到耗时集中在哪一段,比逐台机器排查更快。