跳到主要内容
预计阅读 38 分钟

08|Linux实战

理论再扎实,不会动手也是纸上谈兵。本章将带你掌握 Linux 日常运维中最常用的 Shell 命令、进程管理工具和性能监控手段,并深入 strace/perf 这两把调试利刃。

📋 开篇自测:你已经知道多少?

  1. 如何查看一个进程的 CPU 使用率、内存占用和打开的文件?
  2. top 命令中 load average 的三个数字分别代表什么?多大算”高”?
  3. 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>&1command 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 的延迟。

修复措施

  1. 重启服务临时恢复
  2. --max-old-space-size 限制堆大小,让 OOM 早发现
  3. node --inspect + Chrome DevTools 的 Heap Snapshot 定位泄漏点
  4. 修复代码中的内存泄漏(本例是一个缓存对象没有设置过期时间,无限增长)

这就是一个完整的从发现问题到定位根因的排查链路。关键不在于记住每个命令的参数,而在于建立排查思路:全局概览 → 资源瓶颈 → 问题进程 → 系统调用 → 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 深入       |
|                                                    |
+----------------------------------------------------+

📝 结尾自测:检验你的收获

  1. load average 的三个数字代表什么?如何判断系统是否过载?
  2. top 输出中 us、sy、wa、id 分别代表什么?wa 高说明什么问题?
  3. vmstat 输出中 r、b、si、so 分别代表什么?如何判断内存不足?
  4. strace -c 能统计什么信息?举一个用 strace 排查问题的实际场景。
  5. 描述用 perf 生成火焰图的完整步骤,以及如何解读火焰图。

购买课程解锁全部内容

系统底层入门:10 章掌握操作系统核心

¥29.90