08|Linux实战
理论再扎实,不会动手也是纸上谈兵。本章将带你掌握 Linux 日常运维中最常用的 Shell 命令、进程管理工具和性能监控手段,并深入 strace/perf 这两把调试利刃。
📋 开篇自测:你已经知道多少?
- 如何查看一个进程的 CPU 使用率、内存占用和打开的文件?
- top 命令中 load average 的三个数字分别代表什么?多大算”高”?
- strace 和 perf 分别用于什么场景?
一、Shell 基础与常用命令
💡 已有 Linux 基础? 本节是快速参考。如果你已经熟悉 Shell 命令和管道,可以直接跳到第二节:进程管理工具或第三节:strace/perf 调试。
1.1 Shell 是什么
Shell 是用户与内核之间的桥梁。你在终端敲入的每条命令,都由 Shell 解析后转化为系统调用传给内核执行。
+--------+ +-------+ +--------+
| 用户 | --> | Shell | --> | 内核 |
| 输入命令 | | 解析 | | 执行 |
+--------+ +-------+ +--------+
常见 Shell:
sh -- Bourne Shell (最古老)
bash -- Bourne Again Shell (最常用)
zsh -- Z Shell (macOS默认, 功能最丰富)
fish -- Friendly Interactive Shell
1.2 文件与目录操作
# === 导航 ===
pwd # 显示当前目录
cd /var/log # 切换目录
cd - # 回到上一个目录
cd ~ # 回到家目录
# === 查看 ===
ls -lah # 列出文件 (长格式, 包含隐藏, 人类可读大小)
tree -L 2 # 树形显示目录结构 (深度2层)
stat file.txt # 显示文件详细信息 (inode, 大小, 时间戳)
# === 查找 ===
find /var/log -name "*.log" -mtime -7 # 找7天内修改的.log文件
find / -size +100M -type f # 找大于100MB的文件
locate filename # 快速查找(基于数据库索引)
which python3 # 查找命令的路径
# === 文本处理 ===
cat file.txt # 输出文件内容
head -n 20 file.txt # 前20行
tail -n 20 file.txt # 后20行
tail -f /var/log/syslog # 实时跟踪文件更新
less file.txt # 分页浏览
grep -rn "error" /var/log/ # 递归搜索, 显示行号
grep -E "error|warn" file.log # 正则匹配多个模式
wc -l file.txt # 统计行数
# === 文本处理三剑客 ===
# awk: 按列处理
ps aux | awk '{print $1, $2, $11}' # 输出用户、PID、命令
# sed: 流编辑
sed -i 's/old/new/g' file.txt # 替换文件中的文本
# sort + uniq: 排序去重
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# 统计访问日志中出现最多的10个IP
1.3 管道与重定向
管道和重定向是 Shell 最精妙的设计之一——它们让你可以把简单的命令组合成强大的工具链。
管道 (|):
命令1的输出 --> 命令2的输入 --> 命令3的输入
ps aux | grep nginx | awk '{print $2}'
# 列出进程 -> 过滤nginx -> 提取PID
重定向:
> 覆盖写入文件 echo "hello" > file.txt
>> 追加写入文件 echo "world" >> file.txt
< 从文件读取输入 sort < names.txt
2> 重定向标准错误 command 2> error.log
&> 重定向所有输出 command &> all.log
2>&1 标准错误合并到标准输出 command > log.txt 2>&1
文件描述符:
0 = stdin (标准输入)
1 = stdout (标准输出)
2 = stderr (标准错误)
🤔 想一想
command > file 2>&1和command 2>&1 > file的结果一样吗?为什么?
二、进程管理工具
2.1 查看进程
# ps: 进程快照
ps aux # 所有进程 (BSD风格)
ps -ef # 所有进程 (System V风格)
ps -eo pid,ppid,ni,%cpu,%mem,stat,comm # 自定义输出列
ps aux --sort=-%mem | head -10 # 按内存使用排序前10
# pstree: 进程树
pstree -p # 显示PID
pstree -p 1234 # 显示指定进程的子树
# /proc 文件系统: 进程的"档案馆"
cat /proc/1234/status # 进程状态详情
cat /proc/1234/maps # 进程内存映射
ls -l /proc/1234/fd/ # 打开的文件描述符(符号链接指向实际文件)
cat /proc/1234/cmdline # 启动命令行
cat /proc/1234/environ # 环境变量
2.2 控制进程
# 前后台切换
./my_program # 前台运行
./my_program & # 后台运行
Ctrl+Z # 暂停当前前台进程
bg %1 # 将暂停的任务放到后台运行
fg %1 # 将后台任务调到前台
jobs # 查看当前Shell的后台任务
# 发送信号
kill -15 1234 # 优雅终止 (SIGTERM)
kill -9 1234 # 强制终止 (SIGKILL)
kill -STOP 1234 # 暂停
kill -CONT 1234 # 恢复
killall nginx # 按名称终止
pkill -f "python app.py" # 按模式匹配终止
# nohup: 断开终端后继续运行
nohup ./my_program > output.log 2>&1 &
# 或者使用 screen/tmux 更好的方案
2.3 lsof:万能的文件/网络查看工具
lsof(list open files)是排查问题的”瑞士军刀”,因为在 Linux 中”一切皆文件”:
# 查看进程打开的所有文件
lsof -p 1234
# 查看某个文件被哪些进程打开
lsof /var/log/syslog
# 查看某个端口被谁占用
lsof -i :8080
# 查看某个用户打开的所有文件
lsof -u nginx
# 查看所有网络连接
lsof -i -P -n
# 查看某个目录下被打开的文件 (排查"磁盘空间不释放"问题)
lsof +D /var/log/
三、性能监控
3.1 系统负载概览
# uptime: 最快的系统健康检查
$ uptime
14:32:10 up 45 days, 3:21, 2 users, load average: 2.15, 1.89, 1.62
# load average 三个数字: 1分钟、5分钟、15分钟的平均负载
# 负载值 = 正在运行的进程数 + 等待CPU的进程数 + 等待I/O的进程数
# 经验法则: 负载 < CPU核数 = 健康
# 负载 = CPU核数 = 刚好满载
# 负载 > CPU核数 * 2 = 需要排查
# 查看 CPU 核数
nproc
# 或
lscpu | grep "^CPU(s):"
3.2 top / htop:实时监控
top 输出解读:
top - 14:32:10 up 45 days, load average: 2.15, 1.89, 1.62
Tasks: 203 total, 2 running, 200 sleeping, 0 stopped, 1 zombie
%Cpu(s): 25.3 us, 10.2 sy, 0.0 ni, 62.1 id, 2.0 wa, 0.0 hi, 0.4 si
MiB Mem: 16384.0 total, 2048.0 free, 8192.0 used, 6144.0 buff/cache
MiB Swap: 8192.0 total, 7680.0 free, 512.0 used. 7168.0 avail Mem
CPU行各字段含义:
us (user) : 用户态CPU时间 -- 你的程序代码
sy (system) : 内核态CPU时间 -- 系统调用、内核代码
ni (nice) : 低优先级进程 -- nice值>0的进程
id (idle) : CPU空闲时间 -- 越高越闲
wa (iowait) : 等待I/O时间 -- 高说明磁盘/网络是瓶颈
hi (hardware): 硬件中断时间
si (software): 软件中断时间
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 mysql 20 0 2048000 512000 32000 S 45.2 3.1 120:30.45 mysqld
5678 www 20 0 256000 64000 16000 R 23.1 0.4 30:10.22 nginx
列含义:
VIRT : 虚拟内存总量 (不代表实际使用)
RES : 常驻内存 (实际物理内存占用)
SHR : 共享内存
S : 状态 (R=运行, S=睡眠, D=不可中断, Z=僵尸)
# 常用交互操作
top
# 按 1: 显示每个CPU核心的使用率
# 按 M: 按内存排序
# 按 P: 按CPU排序
# 按 H: 显示线程
# 按 c: 显示完整命令行
# htop: 更好看的替代品
htop
3.3 vmstat:虚拟内存统计
$ vmstat 1 5 # 每秒采样,共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 204800 51200 614400 0 0 50 200 800 1500 25 10 62 2 0
1 1 0 204600 51200 614400 0 0 0 1000 900 1600 30 12 55 3 0
关键字段:
r : 等待CPU的进程数 (持续>CPU核数说明CPU不足)
b : 等待I/O的进程数 (持续>0说明I/O瓶颈)
si : 从swap读入内存的量 (持续>0说明物理内存不足)
so : 从内存写入swap的量
wa : I/O等待占CPU时间百分比
cs : 上下文切换次数/秒 (过高可能是线程太多)
3.4 iostat:磁盘 I/O 统计
$ iostat -xz 1 # 扩展信息, 每秒采样
Device r/s w/s rkB/s wkB/s await %util
sda 50.00 100.00 200.0 800.0 5.20 45.00
nvme0n1 200.00 500.00 800.0 2000.0 0.80 30.00
关键字段:
r/s, w/s : 每秒读/写次数 (IOPS)
rkB/s, wkB/s: 每秒读/写带宽
await : 平均I/O等待时间(ms) -- 越小越好
%util : 设备利用率 -- 接近100%说明磁盘已饱和
3.5 网络监控
# 网络连接状态统计
ss -s # 连接摘要
ss -tnlp # TCP监听端口 + 进程名
ss -tn state established | wc -l # 已建立连接数
# 网络流量
sar -n DEV 1 # 网卡收发速率
iftop # 实时流量(需安装)
# 丢包和错误
netstat -i # 接口统计
cat /proc/net/dev # 网卡收发包计数
🤔 想一想 如果你发现一台服务器响应变慢,你会按什么顺序使用哪些工具来排查?
四、strace:系统调用追踪
strace 能够追踪一个进程执行的所有系统调用,是排查”程序到底在干什么”的神器。
4.1 基本用法
# 追踪一个命令
strace ls /tmp
# 追踪一个正在运行的进程
strace -p 1234
# 只追踪特定类别的系统调用
strace -e trace=open,read,write ls /tmp # 文件操作
strace -e trace=network curl example.com # 网络操作
strace -e trace=process bash # 进程操作
# 统计系统调用耗时和次数
strace -c ls /tmp
# % time seconds usecs/call calls errors syscall
# ------ ----------- ----------- --------- --------- --------
# 40.00 0.000120 10 12 openat
# 25.00 0.000075 5 15 read
# 15.00 0.000045 3 15 close
# 10.00 0.000030 3 10 fstat
# 5.00 0.000015 2 8 mmap
4.2 实战案例
案例1:程序启动慢,找到加载了哪些文件
strace -e trace=openat -T ./my_program 2>&1 | grep -v ENOENT
# -T 显示每个系统调用的耗时
# 输出:
# openat(AT_FDCWD, "/lib/x86_64/libc.so.6", ...) = 3 <0.000015>
# openat(AT_FDCWD, "/etc/my_program.conf", ...) = 4 <0.523000>
# ^^^ 发现读取配置文件花了0.5秒!
案例2:程序卡住了,看看卡在哪里
strace -p $(pgrep my_program)
# 输出:
# futex(0x7f3a2c5b0000, FUTEX_WAIT, ...)
# ^^^ 卡在 futex 上 -- 等待锁! 可能是死锁
五、perf:性能分析
perf 是 Linux 内核自带的性能分析工具,能够精确定位 CPU 热点函数。
5.1 基本用法
# CPU 热点分析
perf top # 实时查看CPU热点函数 (类似top)
perf record -g ./my_program # 采样并记录 (-g 记录调用链)
perf report # 查看分析报告
# 统计硬件事件
perf stat ./my_program
# Performance counter stats for './my_program':
# 2,345,678,901 cycles
# 1,234,567,890 instructions # 1.90 insn per cycle
# 12,345,678 cache-misses # 5.23% of all cache refs
# 234,567,890 cache-references
# 12,345 page-faults
# 523.456 msec task-clock
# 生成火焰图
# 方式一: 使用 perf 内置支持 (Linux 5.8+)
perf record -g -p 1234 -- sleep 30 # 采样30秒
perf script report flamegraph # 直接生成火焰图
# 方式二: 使用 Brendan Gregg 的 FlameGraph 工具
perf script > out.perf # 导出原始数据
./stackcollapse-perf.pl out.perf > out.folded
./flamegraph.pl out.folded > flame.svg # 生成火焰图
5.2 火焰图解读
火焰图 (Flame Graph):
| | |
| func_C (30%) |
| | |
+--func_B (45%)--------+--func_D (25%)-+
| |
+---------- func_A (70%) ----+--func_E (30%)-+
| |
+------------- main (100%) ------------------+
宽度 = 该函数在采样中出现的比例 (越宽越热)
高度 = 调用栈深度
颜色 = 随机分配 (仅用于区分)
看图方法:
1. 从底部开始 (main)
2. 向上看哪个"火焰"最宽 -- 那就是CPU热点
3. 最顶层的宽函数 = 直接消耗CPU最多的函数
六、综合实战:一次 Node.js 服务响应变慢的排查
理论和单个工具的用法都介绍完了,让我们用一个真实的排查案例把它们串起来。假设你是一名后端工程师,线上的一个 Node.js API 服务突然响应变慢,P99 延迟从 50ms 飙到了 2s。
6.1 第一步:全局概览
先用最快的方式看看系统整体健康状况。
$ uptime
10:42:15 up 120 days, 2 users, load average: 12.35, 8.20, 4.10
# load average 急剧上升(这台机器只有 4 核),说明系统最近几分钟严重过载
$ dmesg | tail -20
# [8234567.123] Out of memory: Killed process 2891 (node) total-vm:3245680kB ...
# 发现 OOM Killer 杀掉了一个 node 进程!这是重要线索
6.2 第二步:定位资源瓶颈
$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
8 3 51200 12400 1200 64000 120 80 200 5000 3200 8500 45 25 10 20 0
6 4 52400 10800 1200 62000 150 100 100 6000 3500 9000 40 28 8 24 0
# 关键发现:
# r=8 >> 4核: CPU 严重不足
# si/so 持续 > 0: 正在频繁 swap,物理内存不足
# wa=20-24%: 大量时间等待 I/O
# cs=8500-9000: 上下文切换很高
$ free -h
total used free shared buff/cache available
Mem: 3.7Gi 3.4Gi 62Mi 128Mi 240Mi 120Mi
Swap: 2.0Gi 1.5Gi 512Mi
# 内存几乎耗尽,swap 使用了 1.5G——内存是主要瓶颈
6.3 第三步:找到问题进程
$ top -b -n 1 | head -20
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3012 www 20 0 2845000 2120000 18000 R 85.2 55.8 45:30.12 node
3150 www 20 0 980000 680000 12000 S 35.1 17.9 12:10.45 node
890 mysql 20 0 1200000 520000 28000 S 12.3 13.7 30:20.33 mysqld
# PID 3012 的 node 进程占了 55.8% 内存和 85.2% CPU!
$ cat /proc/3012/status | grep -E "VmRSS|Threads|voluntary"
VmRSS: 2120000 kB
Threads: 18
voluntary_ctxt_switches: 4523890
nonvoluntary_ctxt_switches: 892340
# 2GB 常驻内存,非主动上下文切换很高——CPU 时间片经常被抢占
6.4 第四步:用 strace 看它在干什么
$ strace -cp 3012 -e trace=read,write,futex,mmap 2>&1
# 按 Ctrl+C 中断后查看统计
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- --------
62.00 1.860000 1860 1000 futex
18.00 0.540000 27 20000 read
15.00 0.450000 45 10000 write
5.00 0.150000 150 1000 mmap
# 62% 的时间花在 futex 上!futex 是内核级别的锁等待
# 大量 mmap 调用说明频繁的内存分配/释放
$ strace -p 3012 -e trace=futex -T 2>&1 | head -10
futex(0x7f3a2c500000, FUTEX_WAIT_PRIVATE, 2, NULL) = 0 <0.523000>
futex(0x7f3a2c500000, FUTEX_WAIT_PRIVATE, 2, NULL) = 0 <0.412000>
# 单次锁等待超过 500ms!说明存在严重的锁竞争或阻塞操作
6.5 第五步:用 perf 定位 CPU 热点
$ perf record -g -p 3012 -- sleep 10
$ perf report --stdio | head -40
# Overhead Command Shared Object Symbol
# ........ ....... .................. ............................
# 28.50% node node [.] v8::internal::MarkCompact
# 15.20% node node [.] v8::internal::ScavengeCollector
# 8.30% node libc.so.6 [.] __memmove_avx_unaligned
# 6.10% node node [.] v8::internal::Heap::AllocateRaw
# V8 的 GC(垃圾回收)占了 28.5% + 15.2% = 43.7% 的 CPU!
# memmove 和 AllocateRaw 也很高——说明大量对象分配/移动
6.6 结论与修复
排查链路完整回顾:
uptime → 系统过载 (load >> CPU核数)
dmesg → OOM Killer 已在杀进程
vmstat + free → 内存耗尽,频繁 swap
top → PID 3012 的 node 占 2GB 内存、85% CPU
strace → 62% 时间花在锁等待 (futex),大量 mmap
perf → 43.7% CPU 花在 V8 GC 上
根因:Node.js 服务存在内存泄漏,堆内存持续增长到 2GB,导致 V8 GC 频繁触发 Full GC(MarkCompact)。GC 期间主线程被阻塞(对应 futex 等待),无法处理请求。同时系统物理内存不足开始 swap,进一步放大了 GC 的延迟。
修复措施:
- 重启服务临时恢复
- 用
--max-old-space-size限制堆大小,让 OOM 早发现 - 用
node --inspect+ Chrome DevTools 的 Heap Snapshot 定位泄漏点 - 修复代码中的内存泄漏(本例是一个缓存对象没有设置过期时间,无限增长)
这就是一个完整的从发现问题到定位根因的排查链路。关键不在于记住每个命令的参数,而在于建立排查思路:全局概览 → 资源瓶颈 → 问题进程 → 系统调用 → CPU 热点。
七、一站式排查清单(速查版)
系统变慢了?按此顺序排查:
1. uptime --> 看 load average (是否过载)
2. dmesg | tail --> 看内核日志 (OOM? 硬件错误?)
3. vmstat 1 --> 看 r, b, si, so, wa (CPU/内存/IO)
4. iostat -xz 1 --> 看磁盘 %util, await (IO瓶颈?)
5. free -h --> 看内存和swap使用
6. top --> 找到最耗资源的进程
7. ss -tnlp --> 看网络连接状态
8. strace -p PID --> 追踪问题进程的系统调用
9. perf top --> 看CPU热点函数
常见瓶颈判断:
wa 高 + %util 高 --> 磁盘 I/O 瓶颈
us+sy 高 + id 低 --> CPU 瓶颈
si/so 持续 > 0 --> 内存不足, 频繁 swap
cs 异常高 --> 线程过多, 上下文切换开销大
r >> CPU核数 --> CPU 严重不足
八、本章总结
+----------------------------------------------------+
| Linux 实战核心知识 |
+----------------------------------------------------+
| |
| 文件操作: find, grep, awk, sed, sort, uniq |
| 管道重定向: | > >> 2>&1 |
| |
| 进程管理: ps, pstree, kill, lsof, /proc |
| |
| 性能监控: |
| 全局: uptime, vmstat, iostat, free, sar |
| 进程: top/htop, pidstat |
| 网络: ss, iftop, netstat |
| |
| 调试工具: |
| strace: 追踪系统调用 (程序在做什么) |
| perf: CPU性能分析 (哪里最耗时) |
| 火焰图: 可视化CPU热点 |
| |
| 排查思路: load -> 内核日志 -> CPU/内存/IO |
| -> 找到问题进程 -> strace/perf 深入 |
| |
+----------------------------------------------------+
📝 结尾自测:检验你的收获
- load average 的三个数字代表什么?如何判断系统是否过载?
- top 输出中 us、sy、wa、id 分别代表什么?wa 高说明什么问题?
- vmstat 输出中 r、b、si、so 分别代表什么?如何判断内存不足?
- strace -c 能统计什么信息?举一个用 strace 排查问题的实际场景。
- 描述用 perf 生成火焰图的完整步骤,以及如何解读火焰图。
购买课程解锁全部内容
系统底层入门:10 章掌握操作系统核心
¥29.90