Linux运维岗位面经及其答案第一篇
1. CPU 高怎么排查?
总览流程图
CPU 告警 │ ▼ top / htop 看整体 │ ├── us 高 → 用户态(业务代码)──→ 找进程 → 找线程 → 看调用栈 ├── sy 高 → 内核态(系统调用)──→ 上下文切换?锁竞争? ├── wa 高 → 等 IO ──────────────→ 转磁盘/网络排查 ├── si 高 → 软中断 ─────────────→ 网卡流量?定时器? └── st 高 → 被宿主机偷走 ───────→ 云平台问题
第一步:看整体,判断类型
$ top %Cpu(s): 94.2 us, 2.1 sy, 0.0 ni, 3.5 id, 0.0 wa, 0.0 hi, 0.2 si
| 字段 | 含义 | 高时说明 |
|---|---|---|
| us | 用户态 | 业务代码在疯狂计算(死循环、正则、序列化等) |
| sy | 内核态 | 大量系统调用、锁竞争、上下文切换 |
| wa | IO 等待 | 本质不是 CPU 问题,是磁盘/网络慢 |
| si | 软中断 | 网卡收包多、定时器密集 |
| st | 被偷走 | 虚拟机被宿主机抢占,找云平台 |
💡 先判断类型,再走对应分支,不要盲目找进程。
第二步:分支处理
分支 A:us 高(最常见,占 80% 场景)
逐层定位:进程 → 线程 → 函数/代码行
① 找进程 ② 找线程 ③ 看调用栈 ④ 定位代码
① 找进程
$ top # 按 P 排序(按 %CPU 降序) PID USER %CPU %MEM COMMAND 28467 app 380.0 40.1 java
② 找线程
$ top -Hp 28467 # 查看该进程下所有线程 TID %CPU COMMAND 28489 99.8 java 28490 99.7 java
③ 看调用栈
根据语言选择工具:
| 语言 | 工具 | 命令 |
|---|---|---|
| Java | jstack | printf "0x%x\n" 28489 → jstack 28467 | grep -A30 "0x6f59" |
| C/C++ | perf / gdb | perf top -p 28467 或 gdb -p 28467 → thread apply all bt |
| Go | pprof | curl http://localhost:6060/debug/pprof/profile |
| Python | py-spy | py-spy top --pid 28467 |
| Node.js | --prof / clinic | node --prof app.js → node --prof-process |
| 通用 | perf | perf top -p 28467 / perf record -g -p 28467 |
④ 定位代码并修复
"pool-3-thread-1" nid=0x6f59 runnable java.lang.Thread.State: RUNNABLE at com.example.service.OrderService.calculateDiscount(OrderService.java:128) ← 就是这里
分支 B:sy 高
怀疑方向:上下文切换过多 / 锁竞争 / 系统调用频繁
# 看上下文切换 $ vmstat 1 5 r b swpd free ... in cs us sy id wa st 48 0 0 12048 ... 312 485621 12 38 49 0 1
| 指标 | 正常 | 异常 |
|---|---|---|
cs(上下文切换) | 几千~几万 | >10万 |
r(运行队列) | ≤ 核数 | 远大于核数 |
如果 cs 异常高:
# 看是不是线程太多 $ ps -eLf | wc -l # 看是不是锁竞争(Java) $ jstack <PID> | grep -c "BLOCKED" # 看系统调用热点 $ perf top -e syscalls:sys_enter_* -p <PID> # 或者用 strace 统计系统调用 $ strace -c -p <PID>
| 常见原因 | 解法 |
|---|---|
| 线程池设太大 | 缩小线程池 |
| 锁粒度太粗 | 分段锁 / 无锁结构 |
| 大量短生命周期线程 | 复用线程池 |
| 频繁 futex 调用 | 检查锁竞争 |
分支 C:wa 高
这不是 CPU 问题,是 IO 问题。
# 看哪个磁盘慢 $ iostat -x 1 # 看哪个进程在等 IO $ iotop -oP
转去排查磁盘/网络瓶颈。
分支 D:si 高
# 看软中断分布 $ cat /proc/softirqs # 看网卡流量 $ sar -n DEV 1 # 看是不是单核打满(中断亲和性问题) $ mpstat -P ALL 1
| 常见原因 | 解法 |
|---|---|
| 网卡流量太大 | 限流 / 扩容 |
| 中断都集中在一个核 | 配置 irqbalance 或手动绑核 |
| 定时器太密集 | 检查 timer 相关软中断 |
分支 E:st 高
你的 CPU 被宿主机/其他虚拟机偷走了。
$ top # 看 st 列 %Cpu(s): 5.0 us, 1.0 sy, 0.0 id, 0.0 wa, 0.0 st # st 持续 > 5% → 找云平台
解法:联系云平台 / 换机型 / 升级配置。
第三步:常见根因速查表
| 根因 | 特征 | 定位方法 |
|---|---|---|
| 死循环 | 某线程 100% 且栈不变 | jstack 多次抓取对比 |
| 正则回溯 | us 高,栈在 java.util.regex | jstack 看调用栈 |
| 频繁 GC | us 高,GC 日志频繁 | jstat -gcutil <PID> 1000 |
| 序列化/反序列化 | us 高,栈在 JSON/Protobuf | perf top |
| 锁竞争 | sy 高,大量 BLOCKED | jstack / vmstat |
| 线程过多 | sy 高,cs 极高 | ps -eLf | wc -l |
| 加密运算 | us 高,栈在 SSL/AES | perf top |
| 内存泄漏导致 GC | us 高 + 内存持续增长 | jmap -histo / MAT |
第四步:修复 & 验证
# 修复后观察 $ top # CPU 是否下降 $ vmstat 1 # cs 是否正常 $ jstat -gcutil <PID> 1000 # GC 是否正常(Java)
2. 内存怎么看?
核心命令:free -h
total used free shared buff/cache available Mem: 15Gi 8Gi 1.2Gi 512Mi 6Gi 6.5Gi Swap: 4.0Gi 200Mi 3.8Gi
关键理解:
| 字段 | 含义 |
|---|---|
| used | 进程实际使用的内存 |
| buff/cache | 内核缓冲区 + 页缓存(可回收,不算"真占用") |
| available | 估算的可用内存(free + 可回收的 cache) |
判断标准:
-
看 available 而非 free。available 低才是真缺内存
-
Swap 使用量持续上升 → 内存压力大
进一步排查:
# 看进程内存排序 ps aux --sort=-%mem | head -10 # 看详细内存分布 cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Cached|Buffers|Slab" # 看某进程内存明细 cat /proc/<PID>/smaps_rollup pmap -x <PID>
内存泄漏特征: 进程 RSS 持续增长不回落,可用 valgrind 或 jemalloc 的 heap profiling 定位。
3. Load Average 是什么?
定义: 单位时间内处于 可运行状态(R) 和 不可中断睡眠状态(D) 的进程/线程的平均数。
uptime # 14:30:01 up 30 days, load average: 2.50, 3.10, 4.20 # 1min 5min 15min
三个值含义:
-
1 min:最近 1 分钟的平均负载(反映瞬时压力)
-
5 min:最近 5 分钟(反映短期趋势)
-
15 min:最近 15 分钟(反映长期趋势)
如何判断是否过载:
| 场景 | 判断 |
|---|---|
| Load < CPU 核数 | 正常,有空闲 |
| Load ≈ CPU 核数 | 满负荷 |
| Load > CPU 核数 × 1.5 | 过载,需要关注 |
| Load >> CPU 核数 | 严重过载 |
⚠️ 注意:Load 高不一定是 CPU 高。大量 D 状态(磁盘 IO 等待)的进程也会拉高 Load。
# 查看 D 状态进程
ps aux | awk '$8=="D" {print}'
4. df 和 du 有什么区别?
| 对比项 | df | du |
|---|---|---|
| 视角 | 文件系统(磁盘分区)级别 | 目录/文件级别 |
| 数据来源 | 读取文件系统超级块(superblock) | 遍历目录树逐个统计 |
| 速度 | 快(直接读元数据) | 慢(递归遍历) |
| 包含已删除文件 | ✅ 包含(被进程持有的已删除文件仍占空间) | ❌ 不包含 |
经典不一致场景:
df -h /data # 显示 90% 已满 du -sh /data # 显示只有 50G
原因: 有进程打开了已删除(rm)的文件,文件描述符未释放,空间未归还文件系统。
排查方法:
# 找到被删除但仍被占用的文件 lsof | grep deleted # 释放方法:重启对应进程,或清空文件描述符 > /proc/<PID>/fd/<FD>
5. inode 用完是什么现象?
典型表现:
No space left on device
但用 df -h 看磁盘空间明明还有剩余!
验证:
df -i # 查看 inode 使用率 # Filesystem Inodes IUsed IFree IUse% Mounted on # /dev/sda1 655360 655360 0 100% /
根因: 磁盘空间是按"块"分配的,但每个文件/目录至少要占一个 inode。大量小文件(如海量日志、临时文件、邮件队列)会耗尽 inode。
排查步骤:
# 1. 确认 inode 满了 df -i # 2. 找出哪个目录文件数最多 for d in /var /tmp /home /opt; do echo "$(find $d -xdev | wc -l) $d" done | sort -rn # 3. 进一步下钻 find /var/spool -type f | wc -l
常见场景:
-
/var/spool/postfix邮件堆积 -
/tmp或/var/tmp大量小临时文件 -
定时任务产生海量小日志文件
-
容器层(overlay)产生大量碎片文件
解决方案:
-
清理无用小文件
-
格式化时指定更多 inode:
mkfs.ext4 -N <数量> -
使用 XFS(inode 动态分配,不会预先耗尽)
总结速查表
| 问题 | 第一反应命令 |
|---|---|
| CPU 高 | top → top -Hp → perf |
| 内存不足 | free -h → ps aux --sort=-%mem |
| Load 高 | uptime + `ps aux |
| 磁盘满但 du 对不上 | df -h vs du -sh + `lsof |
| 有空间却写不了文件 | df -i 查 inode |
更多推荐


所有评论(0)