Linux 性能排查分析完全教程

Linux 性能排查分析完全教程

目录

  1. 性能排查方法论
  2. 系统全局概览工具
  3. [CPU 性能分析](#CPU 性能分析)
  4. 内存性能分析
  5. [磁盘 I/O 性能分析](#磁盘 I/O 性能分析)
  6. 网络性能分析
  7. 进程与线程深度分析
  8. 文件系统与内核分析
  9. 高级追踪工具
  10. 内核参数调优
  11. 性能监控体系搭建
  12. 经典案例实战
  13. 性能排查速查表

1. 性能排查方法论

1.1 USE 方法(Utilization, Saturation, Errors)

由 Brendan Gregg 提出,针对每一种资源检查三个维度:

维度 含义 示例
Utilization(利用率) 资源忙碌的时间占比 CPU 使用率 90%
Saturation(饱和度) 排队/溢出的工作 runqueue 长度、swap 使用量
Errors(错误) 错误事件计数 磁盘 I/O 错误、网络丢包

对每种资源逐一排查:CPU → 内存 → 磁盘 → 网络 → 控制器 → 互联。

1.2 RED 方法(Rate, Errors, Duration)

面向服务/请求的排查:

  • Rate:每秒请求数(QPS/TPS)
  • Errors:每秒错误数
  • Duration:每个请求的延迟分布

1.3 排查流程(60 秒法则)

登录服务器后,前 60 秒执行以下命令快速建立全局画像:

bash 复制代码
# 1. 查看系统负载与运行时间
uptime

# 2. 查看内核日志(是否有 OOM、硬件错误)
dmesg -T | tail -50

# 3. 全局统计
vmstat 1 5

# 4. 磁盘 I/O
iostat -xz 1 3

# 5. 内存
free -h

# 6. 网络
sar -n DEV 1 3

# 7. 按 CPU 排序的进程
top -bn1 | head -20

# 8. 按内存排序的进程
ps aux --sort=-%mem | head -15

# 9. 按 I/O 排序的进程
iotop -bn1 | head -15

# 10. 查看是否有僵尸/不可中断进程
ps -eo pid,stat,comm | grep -E '^[[:space:]]*[0-9]+ [DZ]'

1.4 分层排查思维

性能问题可以按系统层级(硬件 → 内核 → 系统 → 应用)逐层下钻。本节用一张分层图帮助你建立『从现象到根因』的排查路径,后面所有工具都挂在对应的层级上。

复制代码
┌─────────────────────────────────────────┐
│           应用层 (Application)           │
├─────────────────────────────────────────┤
│         运行时/框架 (Runtime)             │
├─────────────────────────────────────────┤
│          系统调用 (Syscall)              │
├─────────────────────────────────────────┤
│     内核子系统 (Kernel Subsystems)        │
│   调度器 / 内存管理 / VFS / 网络协议栈      │
├─────────────────────────────────────────┤
│       驱动层 (Drivers)                   │
├─────────────────────────────────────────┤
│       硬件 (Hardware)                    │
└─────────────────────────────────────────┘

问题可能出现在任何一层,排查时自顶向下 定位瓶颈层,再自底向上确认根因。

1.5 关键原则

动手调优或排查前,先记住这几条原则,能避免大量无效操作和误判。

  • 先观察,后干预:不要在未确认瓶颈前盲目调参。
  • 一次只改一个变量:便于归因。
  • 建立基线(Baseline) :没有对比就没有异常。
  • 关注尾延迟(P99/P999) :平均值会掩盖问题。
  • 生产环境慎用高开销工具 :如 strace -f 全量跟踪。

2. 系统全局概览工具

2.1 top / htop

top 是 Linux 自带最基础的实时进程监视器,按 CPU、内存等资源对进程排序,一眼就能找到最忙的进程;htop 是其增强版,支持彩色、鼠标、树状视图和更友好的交互。当你想快速回答『现在系统里是谁在吃资源』时,第一个就该打开它。常用参数:-c 显示完整命令行、-H 展开线程、-p 锁定某进程。

bash 复制代码
top -c          # 显示完整命令行
top -H -p PID   # 查看某进程的线程级 CPU
top -1          # 显示每个 CPU 核心

关键指标解读:

字段 含义
load average 1/5/15 分钟平均运行队列长度(包含 D 状态)
%us 用户态 CPU
%sy 内核态 CPU
%wa I/O wait(等待磁盘)
%si/%hi 软中断/硬中断
%st 被 hypervisor 偷走的时间(虚拟机)

判断标准:

  • load average > CPU 核数 → 存在排队
  • %wa 持续 > 20% → I/O 瓶颈
  • %sy 异常高 → 可能存在频繁系统调用或锁竞争
  • %st > 0 → 宿主机资源争抢

2.2 vmstat

vmstat(virtual memory statistics)提供系统级整体快照:进程、内存、swap、I/O、中断、上下文切换和 CPU 的汇总。它最大的价值是『一眼看全局』------判断瓶颈在 CPU、内存还是 I/O,再决定往下用什么工具深挖。最常用 vmstat 1 每秒刷新一次观察趋势。

bash 复制代码
vmstat 1 10    # 每秒采样,共 10 次
vmstat -w      # 宽格式输出
vmstat -S m    # 以 MB 为单位

关键列:

复制代码
procs  ───memory───  ──swap── ─────io───── ──system── ──────cpu─────
 r  b   swpd  free   si  so    bi    bo    in   cs   us sy id wa st
关注点
r 运行队列中等待 CPU 的进程数,持续 > 核数说明 CPU 不足
b 不可中断睡眠(通常等 I/O)的进程数
si/so swap in/out,非零说明物理内存不足
bi/bo 磁盘读写块数
in/cs 中断次数 / 上下文切换次数
cs 突增 可能是锁竞争、频繁短任务

2.3 sar(System Activity Reporter)

sar(System Activity Reporter)是 sysstat 套件的核心,能采集并历史回放 CPU、内存、I/O、网络等几乎所有子系统指标,默认还会把数据落盘(/var/log/sa)。当你需要『昨天这个点系统什么样』『最近一周的趋势』时,sar 无可替代。注意它通常需要先安装 sysstat 并启动 sa1/sa2 采集服务。

前置:需安装 sysstat,并启用采集服务才能回放历史------RHEL/CentOS 要启动 sysstat 服务(其 sa1/sa2 通过 cron 定时采样落盘到 /var/log/sa/saXX),Debian/Ubuntu 默认已启用。若只装包没起服务,只能看实时、无法用 -f 回放历史。

bash 复制代码
# 安装
yum install sysstat    # RHEL/CentOS
apt install sysstat    # Debian/Ubuntu

# CPU
sar -u 1 5
sar -P ALL 1 3        # 每个核心

# 内存
sar -r 1 5

# 磁盘
sar -d 1 5

# 网络
sar -n DEV 1 5        # 网卡流量
sar -n TCP,ETCP 1 5   # TCP 连接统计
sar -n SOCK 1 5       # socket 统计

# 历史数据(默认保存在 /var/log/sa/)
sar -u -f /var/log/sa/sa15    # 查看15号的数据

sar 输出怎么读:sar -u 看 %user/%system/%iowait/%idle,%iowait 高=CPU 在等 I/O;sar -r 关注 %memused 与 %commit(%commit > 100% 表示申请量超过物理内存,靠 swap/overcommit 撑着);sar -d 每块盘的 %util、await、tps;sar -n DEV 每张网卡的 rxpck/s txpck/s、rxkB/s txkB/s(注意这里 kB 是 1024 进制);sar -n TCP,ETCP 的 retrans/s(重传率,持续 >0 说明网络不稳)、estres/s(被动连接建立失败)。历史回放用 sar -f /var/log/sa/saXX(XX 为日期)。

2.4 dstat(多合一)

dstat 把 vmstat、iostat、netstat、ifstat 的能力合并成一个实时面板,用彩色分列同时展示 CPU、磁盘、网络、内存、系统中断等,最适合想在一屏里同时看多个子系统关联变化的场景。例如 dstat -cdngy 1 就是 CPU + 磁盘 + 网络 + 内存 + 系统每秒刷新。

bash 复制代码
dstat -cdngy 1 5
# -c: CPU  -d: disk  -n: net  -g: page  -y: interrupt
dstat --top-cpu --top-mem --top-io

dstat 输出怎么读:每列对应一个子系统------默认含 CPU(usr/sys/idl/wai/hiq/siq)、磁盘(read/writ)、网络(recv/send)、分页(in/out)、系统(int 中断 / csw 上下文切换);加 -g 看分页、-y 看系统中断。直接看哪一列在动即可快速定位瓶颈域:CPU 列 wai 高→I/O 掣肘,网络列涨→网络繁忙。--top-cpu/--top-mem/--top-io 额外给出最耗资源的进程名。

2.5 atop(带历史回放)

atop 类似 top,但具备历史采样与回放能力:它会周期性记录系统/进程级资源占用到日志(默认 /var/log/atop/),你可以用 atop -r 回放任意历史时刻,定位半夜发生的性能尖刺这类事后排查。实时模式适合持续盯盘,回放模式适合事后取证。

bash 复制代码
atop              # 实时
atop -r /var/log/atop/atop_20240101  # 回放历史
# 按 'm' 切到内存视图, 'd' 磁盘, 'n' 网络

atop 输出怎么读:实时模式下顶栏是系统级 CPU/内存/磁盘/网络汇总,下方进程列表按资源排序,列含 CPU、MEM、DSK、NET 及 RDELAY/WDELAY(I/O 等待毫秒);按 m/d/n 分别切到内存/磁盘/网络专属视图。回放模式 atop -r <文件> 用 t/T 前后翻时间点,适合事后看某时刻谁最忙,是定位半夜尖刺的关键。

2.6 /proc 文件系统(一切数据的源头)

/proc 是一个由内核动态生成的虚拟文件系统,几乎所有性能工具(top、free、vmstat...)的数据源头都在这里。直接读 /proc 里的文件(如 /proc/stat、/proc/meminfo、/proc//*)可以绕过工具封装、拿到最原始最准确的指标。理解 /proc 等于掌握工具背后的真相。

bash 复制代码
/proc/stat          # CPU 统计
/proc/meminfo       # 内存详情
/proc/loadavg       # 负载
/proc/diskstats     # 磁盘统计
/proc/net/dev       # 网卡统计
/proc/net/sockstat  # socket 统计
/proc/<pid>/stat    # 进程状态
/proc/<pid>/status  # 进程详细状态
/proc/<pid>/io      # 进程 I/O 计数
/proc/<pid>/smaps   # 进程内存映射详情
/proc/interrupts    # 中断分布
/proc/softirqs      # 软中断分布
/proc/pressure/     # PSI (Pressure Stall Information, kernel ≥ 4.20)

PSI(Pressure Stall Information)------ 内核 4.20+:

bash 复制代码
cat /proc/pressure/cpu
cat /proc/pressure/memory
cat /proc/pressure/io

输出示例:

复制代码
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 avg60=0.00 avg300=0.00 total=0

some​:至少一个任务在等待该资源;full:所有任务都在等待。这是判断资源压力最直接的指标。


3. CPU 性能分析

3.1 CPU 问题分类

排查 CPU 前先对问题分类,有助于选对工具。本节用表格归纳常见的 CPU 问题类型、典型表现和可能原因,作为后续小节(定位、perf、火焰图...)的导航。

类型 表现 常见原因
用户态 CPU 高 %us 算法低效、死循环、正则回溯
内核态 CPU 高 %sy 频繁系统调用、锁竞争、中断处理
I/O wait 高 %wa 磁盘慢、NFS 卡住
中断风暴 %hi/%si 网卡多队列未配置、硬件故障
上下文切换高 cs 线程过多、锁竞争、频繁调度
单核打满 某一核 100% 单线程瓶颈、中断绑定

3.2 定位高 CPU 进程/线程

当怀疑 CPU 是瓶颈时,第一步是定位------找到消耗 CPU 最高的进程乃至具体线程,再决定用 perf 等工具深入分析。本节给出从 top/ps 到线程级定位的实用命令链。

bash 复制代码
# 找到 CPU 最高的进程
top -bn1 -o %CPU | head -15

# 找到该进程中 CPU 最高的线程
top -H -p <PID>
# 或
ps -mp <PID> -o THREAD,tid,time | sort -rn -k2 | head

# 将线程 ID 转为 16 进制(用于 jstack 等)
printf "%x\n" <TID>

3.3 perf ------ Linux 性能分析瑞士军刀

perf 是 Linux 内核自带的性能分析瑞士军刀,基于硬件 PMU(性能监控单元)和软件事件,能做 CPU 热点、函数级调用栈、缓存命中率、分支预测等分析,是定位『代码哪里慢』的终极工具。它分统计模式(perf stat)、采样模式(perf record + perf report)和实时模式(perf top)。需要先安装 linux-tools/perf 包。

前置与权限:需安装 linux-tools-common + linux-tools-$(uname -r)(Ubuntu)或 perf(RHEL);采集调用栈/符号通常需要 root 或 CAP_PERFMON(内核 5.8+),部分事件(如 cache-misses 的精确归因)还需安装对应内核的 debug 符号包(linux-image-*-dbgsym)。容器里默认无权限,需 --privileged 或赋予 CAP_PERFMON/CAP_BPF。

bash 复制代码
#最标准、最推荐的方法(看发行版信息)
cat /etc/os-release
#怎么看结果:
#看到 ID=ubuntu 或 ID=debian → 用 apt 系列命令。
#看到 ID="rhel" 或 ID="centos" 或 ID="fedora" → 用 yum 或 dnf 系列命令。
# 安装
yum install perf        # RHEL
apt install linux-tools-$(uname -r)  # Ubuntu

# 查看 CPU 热点函数(采样 30 秒)
perf top -g

# 记录并分析
perf record -g -a sleep 30
perf report

# 只记录某进程
perf record -g -p <PID> sleep 10

# 统计硬件事件
perf stat -e cycles,instructions,cache-misses,branch-misses -p <PID> sleep 10

# 查看调度延迟
perf sched record sleep 10
perf sched latency

# 查看锁竞争(需要内核支持)
perf lock record sleep 10
perf lock report

perf stat 关键指标解读:

复制代码
IPC (Instructions Per Cycle) < 1.0  → 可能存在内存瓶颈或分支预测失败
cache-misses / cache-references > 10% → 缓存效率差
branch-misses / branch-instructions > 5% → 分支预测差

3.4 火焰图(Flame Graph)

火焰图(Flame Graph)是 Brendan Gregg 提出的可视化调用栈方法,把 perf/栈采样数据画成横向条形图,宽度代表耗时占比,能一眼看出哪个函数/路径最耗时。它通常配合 perf 或 eBPF 采集栈样本后生成 SVG。注意采样要带 -g(调用图)才能拿到栈。

bash 复制代码
# 安装 FlameGraph 工具
git clone https://github.com/brendangregg/FlameGraph.git

# 生成火焰图
perf record -F 99 -g -p <PID> sleep 30
perf script | ./FlameGraph/stackcollapse-perf.pl > out.folded
./FlameGraph/flamegraph.pl out.folded > flamegraph.svg

# 差分火焰图(对比优化前后)
./FlameGraph/difffolded.pl before.folded after.folded | \
  ./FlameGraph/flamegraph.pl > diff.svg

# 反向火焰图(从叶子到根)
./FlameGraph/flamegraph.pl --reverse out.folded > reverse.svg

3.5 上下文切换分析

上下文切换(context switch)过多会大量消耗 CPU 在切换而非干活上,常见于线程爆炸、锁竞争激烈、I/O 频繁等场景。本节通过 vmstat 的 cs 列和 pidstat -w 区分自愿/非自愿切换,定位切换来源。

bash 复制代码
# 系统级
vmstat 1    # 看 cs 列

# 进程级
pidstat -w 1 5    # 显示每个进程的 cswch/s(自愿)和 nvcswch/s(非自愿)

# 非自愿切换高 → CPU 竞争激烈
# 自愿切换高 → 频繁等待锁/I/O

3.6 中断分析

硬件中断(IRQ)会打断 CPU 当前工作,过多中断(尤其网卡、磁盘)会让 CPU 陷入处理中断而非业务。通过 /proc/interrupts 和 /proc/softirqs 可观察中断分布,配合 irqbalance 或 CPU 亲和性优化。

bash 复制代码
# 查看中断分布
cat /proc/interrupts
watch -n1 cat /proc/interrupts    # 动态观察

# 查看软中断
cat /proc/softirqs

# 查看中断亲和性
cat /proc/irq/<IRQ>/smp_affinity_list

# 修改中断亲和性(绑定到 CPU 0 和 1)
echo 3 > /proc/irq/<IRQ>/smp_affinity

# 使用 irqbalance(自动均衡)
systemctl status irqbalance

# 使用 tuned 或手动脚本做网卡多队列中断绑定

3.7 调度器分析

进程在 CPU 上如何排队、何时被抢占,由内核调度器(CFS 等)决定。调度延迟过高会让进程该跑却没被调度到。本节查看调度策略(chrt)、调度统计(/proc//sched)以及 schedstat,用于诊断调度饥饿或优先级问题。

bash 复制代码
# 查看调度策略
chrt -p <PID>

# 查看进程的调度统计
cat /proc/<PID>/sched

# 查看 CPU 频率调节
cpupower frequency-info
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

# 设置为 performance(避免节能降频影响延迟)
cpupower frequency-set -g performance

3.8 NUMA 分析

现代多路服务器是 NUMA 架构:CPU 访问本地内存快、远端内存慢。进程内存分配跨 NUMA 节点会显著拖慢性能。用 numactl --hardware、numastat 查看拓扑与跨节点访问,必要时用 numactl 绑定或设置内存策略。

bash 复制代码
# 查看 NUMA 拓扑
numactl --hardware
lscpu | grep NUMA

# 查看 NUMA 内存分配
numastat -p <PID>

# 查看 NUMA 命中率
numastat

# 如果 numa_miss 持续增长,考虑绑定进程到本地 NUMA 节点
numactl --cpunodebind=0 --membind=0 <command>

3.9 运行队列深度

运行队列(run queue)长度反映了想跑但等 CPU 的进程数。队列持续过长说明 CPU 算力不足或调度不均。可从 /proc/schedstat、mpstat、top 的 load average 等多角度观察。

bash 复制代码
# 每个 CPU 的运行队列
cat /proc/schedstat | awk 'NR<=3'

# 或使用 mpstat
mpstat -P ALL 1 3

# 查看某 CPU 上等待的进程
ps -eo pid,psr,stat,comm | awk '$3~/R/'

4. 内存性能分析

4.1 内存问题分类

内存类问题表现各异(泄漏、回收、OOM、缓存...),本节用表格归类典型现象与根因,帮助你在 4.2--4.8 各小节间快速定位。

类型 表现 常见原因
内存不足 swap 频繁使用、OOM 内存泄漏、配置不当
内存泄漏 RSS 持续增长不回收 代码 bug、缓存未设上限
页缓存回收 kswapd 高、direct reclaim 内存压力大
大页碎片化 分配 THP 延迟高 内存碎片
NUMA 跨节点 远端内存访问延迟高 未绑定 NUMA

4.2 free / /proc/meminfo

free 快速展示物理内存、swap 的使用概况;/proc/meminfo 则给出几十项内存明细(Cached、Buffers、SReclaimable、AnonPages...)。理解 meminfo 各项是读懂一切内存问题的前提------free 只是入口,meminfo 才是真相。注意 Linux 会尽量用内存做缓存,available 比 free 更能反映真正可用内存。

bash 复制代码
free -h
复制代码
              total    used    free    shared  buff/cache   available
Mem:          125Gi    89Gi    2.1Gi    1.2Gi       33Gi       34Gi
Swap:         8.0Gi    1.2Gi    6.8Gi

关键理解:

  • buff/cache:可回收的缓存,不算真正"被占用"
  • available:内核估算的可用于新进程的内存(含可回收缓存)
  • shared:tmpfs + shmem,不可回收
  • 真正可用 ≈ available,而非 free
bash 复制代码
# 详细内存信息
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Dirty|Writeback|AnonPages|Mapped|Shmem|Slab|SReclaimable|SUnreclaim|PageTables|KernelStack|Committed"

4.3 内存泄漏排查

内存泄漏表现为进程 RSS 随时间只增不减,最终触发 OOM 或拖慢系统。排查思路是持续监控进程 RSS 变化、对比基线、定位到具体模块。本节给出 watch + ps、smem、以及结合 pmap 的定位方法。

bash 复制代码
# 监控进程 RSS 变化
watch -n5 'ps -o pid,rss,vsz,comm -p <PID>'

# 持续记录
while true; do
  echo "$(date) $(ps -o rss= -p <PID>)" >> /tmp/mem_track.log
  sleep 60
done

# 查看进程内存映射
cat /proc/<PID>/smaps | grep -E "^Size|^Rss|^Pss" | awk '{arr[$1]+=$2} END {for (a in arr) print a, arr[a]}' | sort -k2 -rn

# pmap 查看内存段
pmap -x <PID> | sort -k3 -rn | head -20

# 查看堆内存(需要 glibc malloc debug)
gdb -p <PID>
(gdb) call malloc_stats()
(gdb) call malloc_info(0, stdout)

内核态内存泄漏:

bash 复制代码
# 查看 slab 分配器
slabtop -o | head -20
cat /proc/slabinfo | sort -k3 -rn | head

# 使用 kmemleak(需要内核编译开启)
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak

4.4 Swap 与回收

当物理内存紧张,内核会把不常用页换出到 swap(磁盘),或触发页回收(kswapd)。swap 过多使用意味着内存真正不够,且访问被换出页会引发明显卡顿。本节查看 swapon、回收压力(/proc/pressure/memory),并解释 vm.swappiness 的作用。

bash 复制代码
# 查看 swap 使用
swapon -s
free -h

# 查看回收压力
cat /proc/pressure/memory

# 查看 kswapd 活动
sar -B 1 5
# pgpgin/s, pgpgout/s: 页面换入换出
# pgscan/s: 扫描的页面数(高说明回收压力大)
# pgsteal/s: 成功回收的页面数

# vmstat 的 si/so 列
vmstat 1

关键参数:

bash 复制代码
# swappiness: 0-100(全局;cgroup v2 的 memory.swappiness 才支持 0-200),控制 swap 倾向(默认 60)
cat /proc/sys/vm/swappiness
# 数据库服务器通常设为 1 或 10
echo 1 > /proc/sys/vm/swappiness

# 脏页回写阈值
cat /proc/sys/vm/dirty_ratio          # 默认 20%,超过后同步回写
cat /proc/sys/vm/dirty_background_ratio  # 默认 10%,后台回写启动

# OOM 相关
cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/panic_on_oom

4.5 OOM 分析

OOM(Out-Of-Memory)时内核的 OOM Killer 会杀掉占用内存最高的进程以保全系统。本节教你从 dmesg、内核日志中解读 OOM 事件:谁被杀了、当时内存分布如何、是 cgroup 限制还是整机耗尽。

bash 复制代码
# 查看 OOM 日志
dmesg -T | grep -i "oom\|killed process"
journalctl -k | grep -i oom

# 查看进程的 OOM 分数
cat /proc/<PID>/oom_score
cat /proc/<PID>/oom_score_adj    # 可调整,-1000 表示不杀

# 保护关键进程
echo -1000 > /proc/<PID>/oom_score_adj

4.6 页缓存与 Buffer

Linux 用 page cache 缓存文件数据、用 buffer 缓存块设备元数据,这是内存越大文件 IO 越快的原因。缓存占用高通常不是问题(可回收),但某些场景下需要主动释放或限制。本节解读 /proc/meminfo 中 Cached/Buffer 含义及 drop_caches 的正确用法。

bash 复制代码
# 查看页缓存占用
cat /proc/meminfo | grep -E "Cached|Buffers"

# 手动释放页缓存(生产慎用,会导致后续 I/O 突增)
sync
echo 1 > /proc/sys/vm/drop_caches    # 释放页缓存
echo 2 > /proc/sys/vm/drop_caches    # 释放 dentries 和 inodes
echo 3 > /proc/sys/vm/drop_caches    # 释放所有

# 查看文件的缓存状态
vmtouch /path/to/file
vmtouch -v /path/to/directory

4.7 大页(HugePages)

标准 4KB 页在管理大内存时会产生大量 TLB miss 和页表开销;HugePages(2MB/1GB)能显著减少 TLB miss,对数据库、JVM、DPDK 等内存密集型应用收益明显。本节查看与配置 HugePages(/proc/meminfo 的 Huge*、/sys/kernel/mm/hugepages、grub/kernel 参数)。

bash 复制代码
# 查看大页状态
cat /proc/meminfo | grep -i huge
cat /sys/kernel/mm/transparent_hugepage/enabled

# 配置静态大页(如 Oracle/Redis 需要)
echo 4096 > /proc/sys/vm/nr_hugepages    # 分配 4096 个 2MB 大页

# THP(透明大页)对数据库通常有害
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 持久化配置
grubby --update-kernel=ALL --args="transparent_hugepage=never"

4.8 内存带宽与延迟

当 CPU 算力充足但应用仍慢,瓶颈可能在内存墙------内存带宽耗尽或访问延迟过高(NUMA 跨节点、频繁 cache line 争用)。本节用 Intel MLC(Memory Latency Checker)等工具测量带宽/延迟,定位是否内存子系统成为天花板。

bash 复制代码
# 使用 Intel MLC (Memory Latency Checker)
./mlc --bandwidth_matrix
./mlc --loaded_latency

# 使用 perf 查看内存访问模式
perf stat -e LLC-load-misses,LLC-store-misses -p <PID> sleep 10

# 使用 numactl 测试跨 NUMA 延迟
numactl --hardware    # 查看节点间距离

5. 磁盘 I/O 性能分析

5.1 I/O 问题分类

I/O 瓶颈分磁盘吞吐、延迟、IOPS、文件系统、网络存储等多个维度,本节表格归类,作为 5.2--5.10 的索引。

类型 表现 常见原因
吞吐瓶颈 IOPS/带宽打满 磁盘慢、RAID 降级
延迟高 await 高 队列深、磁盘慢
I/O 调度不当 某些进程饥饿 调度器不匹配工作负载
文件系统瓶颈 元数据操作慢 journal 争抢、碎片
写放大 实际写入 >> 逻辑写入 日志、COW、对齐问题

5.2 iostat

iostat(sysstat 套件)是分析块设备 I/O 的标配,输出每个磁盘的 %util、await、r/s、w/s、rKB/s 等。核心看 %util(设备忙否)和 await/r_await/w_await(延迟)。最常用 iostat -xz 1,配合 -d 只看设备。

bash 复制代码
iostat -xz 1 5

关键列解读:

含义 关注阈值
r/s, w/s 每秒读/写 IOPS 对比磁盘规格
rkB/s, wkB/s 每秒读/写吞吐 对比磁盘带宽
rrqm/s, wrqm/s 合并的请求数 高说明顺序 I/O
await 平均 I/O 等待时间(ms) HDD > 20ms 关注,SSD > 5ms 关注
r_await, w_await 读/写分别的等待时间
avgqu-sz 平均队列深度 > 磁盘并发能力则饱和
%util 设备利用率 100% 不一定饱和(SSD 可并发)
aqu-sz 平均活动 I/O 数

注意: %util​ 对 SSD/NVMe 意义有限,因为它们支持高并发。应结合 await 和队列深度判断。

5.3 iotop(进程级 I/O)

iostat 看的是设备,iotop 看的是进程------它像 top 一样按进程/线程展示实时磁盘读写速率,帮你回答是哪个进程在狂写磁盘。常用 -o(只显示有 IO 的)、-P(按进程)、-a(累计)。

bash 复制代码
iotop -oPa    # 只显示有 I/O 的进程,累计
iotop -obtqqq -d 1

iotop 输出怎么读:默认列含 DISK READ、DISK WRITE(瞬时速率)、SWAPIN、IO(进程等待 I/O 的时间占比);-o 只看有 I/O 的进程、-P 按进程聚合(否则按线程)、-a 显示累计量。持续 IO> 列偏高的进程即为 I/O 热点;SWAPIN 高说明在大量换入,通常伴内存压力。

5.4 pidstat(进程 I/O 统计)

pidstat(sysstat)是进程级全能统计工具,可分别看进程的 CPU(-u)、内存(-r)、I/O(-d)、上下文切换(-w)、线程(-t)。当你已锁定某进程、要量化它的各项资源消耗趋势时,pidstat 1 5 是日常首选。

bash 复制代码
pidstat -d 1 5    # 每个进程的 kB_rd/s, kB_wr/s
pidstat -d -p <PID> 1

pidstat 输出怎么读:-d 给出每进程的 kB_rd/s(读吞吐)、kB_wr/s(写吞吐)、kB_ccwr/s(因脏页回收而取消的写);-u 给 %usr/%system/%guest 与 CPU 占用;-w 给 cswch/s(自愿切换,多因等锁/I/O)与 nvcswch/s(非自愿,CPU 被抢占);-r 给 minflt/s majflt/s(缺页)、VSZ RSS;加 -t 可下钻到线程级。每项都带时间窗口(如 1 5 表示每秒采样共 5 次)。

5.5 blktrace / btrace(块层追踪)

blktrace 在块设备层做精细化追踪,记录每个 I/O 请求从提交、入队、合并、分发到完成的全生命周期,再用 blkparse/btt 分析各阶段耗时。当 iostat 显示 await 很高、你想知道时间到底耗在队列还是设备时,它就是答案。

前置与权限:需 blktrace/blkparse 包,且 debugfs 已挂载(通常 /sys/kernel/debug);运行需 root。btrace 是其简化封装。trace 数据量大,建议定向到文件并限定时间(如 blktrace -d /dev/sda -w 10)。

bash 复制代码
# 抓取块设备 I/O 事件
blktrace -d /dev/sda -o - | blkparse -i - > blktrace.txt

# 或使用 btrace(简化版)
btrace /dev/sda

# 分析工具
btt -i sda.blktrace.*    # 生成延迟统计

5.6 I/O 调度器

内核 I/O 调度器决定块请求如何合并与排序,影响吞吐与延迟的取舍。常见调度器:mq-deadline(通用)、none/noop(SSD/NVMe)、bfq(桌面交互)。本节查看与切换调度器(/sys/block//queue/scheduler),并为不同介质给建议。

bash 复制代码
# 查看当前调度器
cat /sys/block/sda/queue/scheduler
# [mq-deadline] kyber bfq none

# 修改
echo mq-deadline > /sys/block/sda/queue/scheduler

# 推荐:
# SSD/NVMe → none 或 mq-deadline
# HDD → mq-deadline 或 bfq
# 数据库 → mq-deadline 或 none

5.7 文件系统级分析

同样一块磁盘,不同文件系统的碎片、日志、特性会带来不同性能。本节从文件系统视角排查:filefrag(碎片)、df/挂载选项、inode 耗尽、日志模式等,弥补只看设备指标的盲区。

bash 复制代码
# ext4 碎片检查
filefrag -v /path/to/file

# XFS 碎片
xfs_db -r -c frag /dev/sda1

# 文件系统 I/O 延迟追踪
# 使用 eBPF/bcc 工具(见后文)

# 查看文件系统挂载选项
mount | grep /data
cat /proc/mounts

# 关键选项:
# noatime: 不更新访问时间(减少写)
# nobarrier: 关闭写屏障(SSD 有电容时可考虑)
# data=writeback: ext4 减少 journal 写入

5.8 磁盘健康检查

磁盘本身老化或故障会表现为诡异的 I/O 延迟/错误。用 smartctl 读取 SMART 健康信息(重分配扇区、温度、通电时间)可提前发现坏盘;结合 dmesg 中的 ATA/SCSI 错误判断是否硬件问题。

bash 复制代码
# SMART 信息
smartctl -a /dev/sda
smartctl -H /dev/sda    # 快速健康检查

# 查看坏道重映射
smartctl -a /dev/sda | grep -i "reallocated\|pending\|uncorrect"

# 查看 I/O 错误
dmesg | grep -i "error\|fault\|reset\|timeout" | grep -i "sd\|nvme\|blk"
cat /sys/block/sda/stat    # 注意:该文件无错误计数字段(第10列为 io_ticks)。磁盘错误看 dmesg / smartctl

5.9 NVMe 专项

NVMe 固态盘延迟低至微秒、队列深度大,传统 HDD 调优思路不适用。本节用 nvme-cli 查看设备信息、SMART、命名空间、固件,并针对 NVMe 给出中断亲和、队列、IO 调度等专项建议。

bash 复制代码
# NVMe 设备信息
nvme list
nvme smart-log /dev/nvme0n1

# NVMe 队列深度
cat /sys/block/nvme0n1/queue/nr_requests

# NVMe 命名空间
nvme id-ns /dev/nvme0n1

5.10 写回与刷盘

脏页(dirty page)由内核回写线程(pdflush/Writeback)按阈值周期性刷到磁盘。刷盘策略不当会导致突发卡顿或数据丢失风险。本节解读 /proc/meminfo 的 Dirty、/proc/sys/vm/dirty_* 参数,以及回写线程状态。

bash 复制代码
# 查看脏页
cat /proc/meminfo | grep Dirty

# 查看回写线程
ps aux | grep -E "flush|writeback"

# 调整回写参数
echo 10 > /proc/sys/vm/dirty_background_ratio
echo 20 > /proc/sys/vm/dirty_ratio
echo 500 > /proc/sys/vm/dirty_expire_centisecs    # 脏页存活时间(1/100秒)
echo 1000 > /proc/sys/vm/dirty_writeback_centisecs  # 回写线程唤醒间隔

6. 网络性能分析

6.1 网络问题分类

网络问题涵盖吞吐、延迟、丢包、连接数、DNS、TCP 异常等,本节表格归类,作为 6.2--6.9 的导航。

类型 表现 常见原因
带宽打满 吞吐量接近网卡上限 流量过大、未做限流
延迟高 RTT 增大 路由问题、队列缓冲
丢包 retransmit 增加 拥塞、网卡 ring buffer 溢出
连接数多 TIME_WAIT 堆积 短连接过多
软中断高 %si 高、ksoftirqd 忙 单核处理所有中断

6.2 基础网络统计

排查网络先要有整体视图:网卡流量、错误/丢包、协议分布、吞吐。本节汇总 sar -n、ifstat、nload、/proc/net/dev 等基础统计手段,快速判断网络是否饱和或存在错误。

bash 复制代码
# 网卡流量
sar -n DEV 1 5
ifstat 1
nload eth0

# 网络接口错误
ip -s link show eth0
ethtool -S eth0 | grep -i "error\|drop\|miss\|fifo"

# 协议栈统计
cat /proc/net/softnet_stat
# 第 1 列: 处理的包数
# 第 2 列: 丢弃的包数(非零 = 队列溢出)
# 第 3 列: time_squeeze(软中断预算用完)

nstat -az | grep -i "drop\|error\|overflow\|retrans"
netstat -s | grep -i "error\|drop\|retrans\|overflow"

6.3 TCP 连接分析

ss 是取代 netstat 的现代工具,能高效列出套接字状态、连接数、端口占用。本节用 ss -s 看整体连接统计、ss -tan 按状态归类,定位 TIME_WAIT 堆积、端口耗尽、半连接等问题。

bash 复制代码
# 连接状态统计
ss -s
ss -tan | awk 'NR>1{print $1}' | sort | uniq -c | sort -rn

# 查看 TIME_WAIT
ss -tan state time-wait | wc -l

# 查看 ESTABLISHED 连接
ss -tan state established | wc -l

# 查看某端口的连接
ss -tanp | grep :8080

# 查看 TCP 重传
nstat -az TcpRetransSegs
netstat -s | grep retrans

# 查看 TCP 队列溢出
nstat -az TcpExtListenOverflows TcpExtListenDrops
netstat -s | grep "listen"

ss 输出怎么读:ss -s 是汇总(总 TCP、ESTAB、TIME-WAIT 等数量);ss -tan 每行 State + 本地:端口 + 对端:端口 + Recv-Q/Send-Q------对 ESTABLISHED 连接,Recv-Q 是已收但未交给应用的字节、Send-Q 是已发但未获对端确认(ACK)的字节,二者持续非零说明收发不及时(应用慢或网络拥塞);ss -tanp 额外显示进程。常用状态:ESTAB 已建立、TIME-WAIT 主动关闭方等待、CLOSE-WAIT 被动方未关、SYN-SENT/RECV 握手中、LISTEN 监听。

6.4 抓包与深度分析

tcpdump 在网络接口抓包,是定位包到底有没有到/走了什么的最终手段;tshark(命令行 Wireshark)可在服务端做协议级深度解析。本节给出常用抓包过滤表达式与保存/回放方法。

bash 复制代码
# tcpdump 抓包
tcpdump -i eth0 -nn -c 100 port 80
tcpdump -i eth0 -w /tmp/capture.pcap    # 保存

# 分析重传
tshark -r capture.pcap -Y "tcp.analysis.retransmission"

# 分析延迟
tshark -r capture.pcap -q -z conv,tcp

# 使用 Wireshark GUI 分析
scp capture.pcap user@local:~

6.5 网络延迟排查

网络慢可能是链路延迟、路由绕路、或中间设备限速。本节用 ping(RTT)、traceroute/mtr(逐跳延迟)、以及 TCP 层面的重传/RTT 分析,分层定位延迟来源。

bash 复制代码
# ping 延迟
ping -c 100 target_ip | tail -1

# 路由追踪
traceroute target_ip
mtr -r -c 100 target_ip

# TCP 连接延迟
curl -o /dev/null -s -w "DNS: %{time_namelookup}\nConnect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal: %{time_total}\n" http://target

# 使用 tcpretrans (bcc) 追踪重传
tcpretrans

6.6 网卡调优

网卡硬件参数是高吞吐(尤其 10G/25G+)场景的关键:ring buffer、offload(TSO/GRO/LRO)、中断亲和、队列数。本节用 ethtool 查看/调整这些参数,缓解丢包与 CPU 软中断瓶颈。

bash 复制代码
# 查看 ring buffer
ethtool -g eth0
ethtool -G eth0 rx 4096 tx 4096

# 多队列
ethtool -l eth0
ethtool -L eth0 combined 8

# 中断绑定(将不同队列绑定到不同 CPU)
# 查看 IRQ 号
grep eth0 /proc/interrupts
# 绑定
echo 2 > /proc/irq/<IRQ>/smp_affinity_list

# 使用 RPS/RFS(软件多队列)
echo ffff > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

# 关闭 GRO/LRO(排查时)
ethtool -K eth0 gro off lro off

# 开启/关闭 offload
ethtool -K eth0 tso on gso on

6.7 内核网络参数

大量网络性能/稳定性行为由内核 sysctl 参数控制:TCP 缓冲区大小、TIME_WAIT 复用、backlog、conntrack 限制等。本节列出最常用的一批 net.* 参数及其调优含义。

bash 复制代码
# TCP 缓冲区
sysctl net.core.rmem_max net.core.wmem_max
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem

# 连接队列
sysctl net.core.somaxconn          # listen 队列上限
sysctl net.ipv4.tcp_max_syn_backlog

# TIME_WAIT 相关
sysctl net.ipv4.tcp_tw_reuse       # 允许复用 TIME_WAIT
sysctl net.ipv4.tcp_max_tw_buckets

# 连接跟踪(conntrack)
sysctl net.netfilter.nf_conntrack_max
sysctl net.netfilter.nf_conntrack_tcp_timeout_established
cat /proc/sys/net/netfilter/nf_conntrack_count

# 如果 conntrack 表满
dmesg | grep "table full"
echo 262144 > /proc/sys/net/netfilter/nf_conntrack_max

6.8 网络带宽测试

iperf3 是标准的端到端带宽/吞吐测试工具,分服务端(-s)与客户端(-c),可测 TCP/UDP 带宽、抖动、丢包。本节给出点对点带宽压测的基本用法,用于验证链路真实容量。

bash 复制代码
# iperf3
iperf3 -s                    # 服务端
iperf3 -c server_ip -t 30 -P 4   # 客户端,4 并发,30 秒

# 测试 UDP 丢包
iperf3 -c server_ip -u -b 1G

# 测试延迟
sockperf ping-pong -i server_ip -p 11111

6.9 DNS 排查

DNS 解析慢或失败会表现为应用卡在连接前。用 dig、nslookup、time 测量解析耗时,检查 resolv.conf、DNS 服务器、缓存(nscd/systemd-resolved),定位解析瓶颈。

bash 复制代码
# 测试 DNS 解析时间
dig example.com
time nslookup example.com

# 查看 nscd/systemd-resolved 缓存
systemctl status systemd-resolved
resolvectl statistics

# strace 查看 DNS 系统调用(grep ":53" 即按 DNS 服务端口 53 过滤网络系统调用)
strace -e trace=network -p <PID> 2>&1 | grep ":53"

7. 进程与线程深度分析

7.1 进程状态解读

进程状态(R/S/D/Z/T)藏着大量线索:D 是不可中断睡眠(常卡在 I/O)、Z 是僵尸、R 排队说明 CPU 不够。本节解读 ps 状态字段、wchan(卡在哪个内核函数),是进程级排查的基本功。

bash 复制代码
ps -eo pid,ppid,user,stat,wchan:32,pcpu,pmem,rss,vsz,etime,comm | head -20
STAT 含义
R Running(运行中或可运行)
S Sleeping(可中断睡眠)
D Disk sleep(不可中断睡眠,通常等 I/O)
Z Zombie(僵尸进程)
T Stopped(被信号停止)
I Idle(内核空闲线程)
+ 前台进程组
< 高优先级
N 低优先级
L 有页面锁定在内存

大量 D 状态进程 → I/O 问题或 NFS 挂载卡住。

7.2 strace(系统调用追踪)

strace 追踪进程发出的系统调用(open/read/write/connect...)及其返回值、耗时,是应用卡在哪一步的利器。-c 做统计(低开销)、-p 挂到运行进程、-T 看每次调用耗时、-e 过滤 syscall。注意它会显著拖慢目标进程。

前置与权限:需 ptrace 权限(root 或 CAP_SYS_PTRACE)。注意容器环境常受限:若启用 seccomp 或 kernel.yama.ptrace_scope=1,strace 可能只能追踪自身派生的子进程,无法附加到已有进程(-p 失败)。高负载进程用 -f 全量跟踪会严重拖慢目标,优先用 -c 统计或 -e trace= 收窄。

bash 复制代码
# 追踪进程的系统调用
strace -p <PID> -c           # 统计模式(低开销)
strace -p <PID> -tt -T       # 显示时间戳和耗时
strace -p <PID> -e trace=network    # 只追踪网络相关
strace -p <PID> -e trace=file       # 只追踪文件操作
strace -p <PID> -e trace=%desc      # 文件描述符相关

# 追踪并附加子进程
strace -f -p <PID>

# 追踪新启动的命令
strace -f -tt -o /tmp/trace.log <command>

# 统计系统调用耗时
strace -cp <PID> sleep 10

strace 输出示例解读:

复制代码
14:23:01.123456 read(3, "data...", 4096) = 4096 <0.000012>
#                    fd  缓冲区  大小    返回值  耗时12微秒

⚠️ 警告: strace 开销极大(10-100x 减速),生产环境慎用,尽量用 -c​ 统计模式或限定 -e trace=

7.3 ltrace(库函数追踪)

ltrace 类似 strace,但追踪的是用户态库函数调用(如 malloc/free/printf),适合定位库层面而非系统调用层面的行为(如内存分配热点)。常用 -c 统计、-e 过滤。

bash 复制代码
ltrace -p <PID> -c
ltrace -p <PID> -e malloc,free,open

7.4 /proc/ 深度挖掘

每个进程在 /proc// 下都有一整套内核暴露的信息:status(内存/线程)、fd(打开的文件描述符)、maps(内存映射)、io(读写统计)、stack(内核栈)、cmdline。本节演示如何直接读这些文件做深度进程画像,无需额外工具。

bash 复制代码
PID=12345

# 基本信息
cat /proc/$PID/status
cat /proc/$PID/stat

# 打开的文件描述符
ls -la /proc/$PID/fd | wc -l
ls -la /proc/$PID/fd | head -20

# 文件描述符限制
cat /proc/$PID/limits | grep "open files"

# 内存映射
cat /proc/$PID/maps | head -30
cat /proc/$PID/smaps_rollup

# I/O 统计
cat /proc/$PID/io

# 线程
ls /proc/$PID/task/
cat /proc/$PID/task/*/stat | awk '{print $1, $2, $14+$15}' | sort -rn -k3 | head

# 网络连接
cat /proc/$PID/net/tcp | wc -l

# cgroup 归属
cat /proc/$PID/cgroup

# 环境变量
cat /proc/$PID/environ | tr '\0' '\n'

# 工作目录和可执行文件
ls -la /proc/$PID/cwd /proc/$PID/exe

# 信号屏蔽
cat /proc/$PID/status | grep Sig

7.5 僵尸进程处理

僵尸进程(Z 状态)已退出但父进程没回收其资源,大量堆积会耗尽 PID。本节给出定位僵尸及其父进程、通过重启父进程或发送 SIGCHLD 来清理的方法。

bash 复制代码
# 找到僵尸进程
ps -eo pid,ppid,stat,comm | grep Z

# 找到其父进程
ps -o pid,ppid,comm -p <zombie_pid>

# 通知父进程回收
kill -SIGCHLD <parent_pid>

# 如果父进程不处理,杀父进程让 init 回收
kill <parent_pid>

7.6 线程分析

现代服务多为多线程,瓶颈常在某几个线程。本节用 ps -T、top -H 查看线程、结合 /proc//task 分析线程栈与资源,定位哪个线程在忙。

bash 复制代码
# 查看进程的所有线程
ps -T -p <PID>
top -H -p <PID>

# 查看线程栈
cat /proc/<PID>/task/<TID>/stack    # 内核栈(需 root)

# 用户态栈
gdb -p <PID>
(gdb) info threads
(gdb) thread apply all bt

# Java 进程
jstack <PID>
jstack -l <PID> > /tmp/thread_dump.txt

# Go 进程
kill -SIGQUIT <PID>    # 打印 goroutine 栈到 stderr
# 或设置 GOTRACEBACK=all

# Python 进程
py-spy dump --pid <PID>
py-spy top --pid <PID>

7.7 文件描述符泄漏

进程或系统打开的 fd 超过限制会导致 too many open files。本节查看进程 fd 数(/proc//fd)、系统级限制(fs.file-nr、ulimit -n),定位 fd 泄漏(常见于连接/文件未关闭)。

bash 复制代码
# 查看进程 fd 数量
ls /proc/<PID>/fd | wc -l

# 查看系统级 fd
cat /proc/sys/fs/file-nr
# 已分配  未使用  最大值

# 查看 fd 限制
ulimit -n
cat /proc/sys/fs/file-max

# 查看谁打开了某文件
lsof /path/to/file
fuser -v /path/to/file

# 查看已删除但仍被占用的文件(空间未释放)
lsof +L1 | grep deleted

8. 文件系统与内核分析

8.1 文件系统性能

文件系统是 I/O 之上的抽象层,其挂载选项、日志模式、特性直接影响性能。本节从文件系统层面排查(挂载参数、journal、特性开关),与 5.x 设备层形成互补。

bash 复制代码
# 查看文件系统类型和选项
df -Th
mount | grep /data

# inode 使用
df -i

# 目录项缓存
cat /proc/sys/fs/dentry-state
cat /proc/sys/fs/inode-nr

# 文件系统 I/O 延迟(bcc 工具)
ext4slower 10     # 显示 >10ms 的 ext4 操作
xfsslower 10
biolatency        # 块设备 I/O 延迟直方图
biosnoop          # 每次 I/O 的详细信息

8.2 VFS 层分析

VFS(虚拟文件系统)是应用与具体文件系统之间的统一抽象层。VFS 层的锁竞争、dentry 缓存、inode 争用都可能成为瓶颈。本节用 trace/perf 观察 VFS 相关函数开销。

bash 复制代码
# 使用 bcc 工具
vfsstat 1         # VFS 操作统计
vfscount 10       # 10 秒内 VFS 调用计数
fileslower 10     # 慢文件操作
filetop -C 5      # 按文件统计 I/O

# 使用 ftrace(先进入 tracefs 挂载点,与 9.3 ftrace 用法风格统一)
cd /sys/kernel/debug/tracing
echo 1 > events/fs/enable
cat trace_pipe

8.3 锁与同步分析

内核或应用中的锁竞争会让并行变串行,表现为 CPU 空转等待。本节用 perf、eBPF 等观察锁的持有/等待时间(如 futex、spinlock、rwsem),定位同步瓶颈。

bash 复制代码
# 内核锁竞争(需要 CONFIG_LOCKDEP 或 CONFIG_LOCK_STAT)
cat /proc/lock_stat

# 使用 perf
perf lock record sleep 10
perf lock report

# 使用 bcc
funclatency 'mutex_lock' 10    # mutex_lock 延迟分布

# 用户态锁竞争(需要应用支持)
# Java: jstack 查看 BLOCKED 线程
# C/C++: 使用 valgrind --tool=helgrind 或 ThreadSanitizer

8.4 内核日志分析

dmesg / journalctl 记录了内核的运行事件与警告:OOM、I/O 错误、软锁、RCU stall、硬件异常。本节归纳排查性能问题时最该 grep 的关键词与套路。

bash 复制代码
dmesg -T --level=err,warn | tail -50
journalctl -k -p warning --since "1 hour ago"

# 常见关键信息:
# "Out of memory" → OOM
# "I/O error" → 磁盘问题
# "BUG:" / "WARNING:" → 内核 bug
# "hung_task" → 任务卡住超过 120 秒
# "soft lockup" → CPU 被占用超过 20 秒未调度
# "RCU detected stall" → RCU 回调积压
# "nf_conntrack: table full" → 连接跟踪表满

8.5 hung task 分析

内核 hung task 指某任务在 D 状态(不可中断)超过阈值(默认 120s),通常卡在 I/O 或锁上。本节解读 hung task 告警、结合栈与块设备/I/O 状态定位根因。

bash 复制代码
# 内核参数:超过 120 秒处于 D 状态则报告
cat /proc/sys/kernel/hung_task_timeout_secs

# dmesg 中搜索
dmesg | grep -A 20 "hung_task"

# 查看 D 状态进程的内核栈
for pid in $(ps -eo pid,stat | awk '$2~/D/{print $1}'); do
  echo "=== PID $pid ==="
  cat /proc/$pid/stack
  cat /proc/$pid/wchan
  echo
done

8.6 cgroup 分析

cgroup(尤其 cgroup v2)对 CPU、内存、I/O、进程数设限,容器/systemd 都依赖它。进程被限流常源于 cgroup 配额(cpu.max、memory.max、io.max)。本节查看 cgroup 层级与当前用量,排查整机有资源但容器用不上的问题。

bash 复制代码
# cgroup v2 查看资源使用
cat /sys/fs/cgroup/system.slice/<service>.service/cpu.stat
cat /sys/fs/cgroup/system.slice/<service>.service/memory.current
cat /sys/fs/cgroup/system.slice/<service>.service/io.stat

# cgroup v1
cat /sys/fs/cgroup/cpu/docker/<container_id>/cpuacct.usage
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.usage_in_bytes

# systemd-cgtop(类似 top 的 cgroup 视图)
systemd-cgtop

9. 高级追踪工具

选型指引(BCC / bpftrace / ftrace / SystemTap 怎么选):四者都用于动态追踪,但适用场景不同。BCC 与 bpftrace 都基于 eBPF(主流内核 ≥ 4.9 可用,部分特性需更高版本),是新项目首选------BCC 提供大量开箱即用工具(biosnoop、tcptop、execsnoop...),适合直接查;bpftrace 用类 awk 的单行/脚本语法,适合临时写探针验证假设。ftrace 随内核自带、无需安装,走 tracefs(/sys/kernel/debug/tracing),适合无 eBPF 环境或需要内核函数级细节(调度、唤醒路径)。SystemTap 老牌但强依赖与运行内核完全匹配的 debuginfo,版本一变极易失败,仅老内核/特定发行版才考虑。结论:新环境一律优先 eBPF。

9.1 BCC(BPF Compiler Collection)

BCC(BPF Compiler Collection)是基于 eBPF 的高级工具集,提供现成的 Python/C 工具(如 execsnoop、biosnoop、tcplife),无需写内核模块即可在内核态高效采集数据。它是现代 Linux 动态追踪的事实标准,覆盖调度、I/O、网络、锁等几乎所有层面。

前置与权限:需内核 ≥ 4.9 且开启 CONFIG_BPF 等相关选项;安装 bcc-tools/bpfcc-tools 及内核头文件 linux-headers-$(uname -r);运行需 root。部分工具读取内核内部结构体,若内核版本与头文件不匹配可能报错,必要时装 linux-image-*-dbgsym。容器内需 --privileged 或 CAP_BPF/CAP_PERFMON。

bash 复制代码
# 安装
yum install bcc-tools          # RHEL/CentOS
apt install bpfcc-tools        # Debian/Ubuntu
# 工具位于 /usr/share/bcc/tools/

# ===== CPU =====
execsnoop          # 追踪新进程执行
runqlat 10 1       # 运行队列延迟直方图
runqlen 10 1       # 运行队列长度分布
cpudist 10 1       # 进程在 CPU 上的时间分布
offcputime 10      # 进程不在 CPU 上的时间及原因(阻塞分析)
profile 30         # CPU 采样(生成火焰图数据)
softirqs 10 1      # 软中断耗时

# ===== 内存 =====
memleak 10         # 内存泄漏追踪
oomkill            # 追踪 OOM 事件
slabratetop 10     # slab 分配速率 top
pagein             # 追踪页面换入

# ===== I/O =====
biolatency 10 1    # 块 I/O 延迟直方图
biosnoop           # 每次块 I/O 详情
biostacks          # I/O 发起栈
filetop -C 5       # 文件 I/O top
fileslower 10      # 慢文件操作
ext4dist 10 1      # ext4 操作延迟分布
xfsslower 10       # XFS 慢操作
zfsdist 10 1       # ZFS 延迟分布
cachestat 1        # 页缓存命中率

# ===== 网络 =====
tcptop 5           # TCP 连接流量 top
tcpconnect         # 追踪新 TCP 连接
tcpaccept          # 追踪 accept
tcpretrans         # 追踪 TCP 重传
tcpdrop            # 追踪 TCP 丢包
tcpconnlat         # TCP 连接延迟
tcplife            # TCP 连接生命周期
udpsnoop           # UDP 包追踪
dnsreqs            # DNS 请求追踪

# ===== 调度/锁 =====
offwaketime 10     # 阻塞时间 + 唤醒栈
funccount 'vfs_*'  # 函数调用计数
funclatency 'vfs_read' 10  # 函数延迟分布
stackcount 'tcp_sendmsg'  # 调用栈计数

memleak(bcc)前置与权限:依赖内核 eBPF 支持(基础功能 ≥ 4.9,部分特性需更高版本)以及与当前运行内核匹配的 kernel-headers;若栈回溯 / 符号不全,需安装对应 linux-image-*-dbgsym​。运行需 root,或内核 ≥ 5.8 时授予 CAP_BPF / CAP_PERFMON。注意它不是内核自带的 kmemleak(后者用 /sys/kernel/debug/kmemleak,需编译开启)。

9.2 bpftrace(高级 eBPF 脚本)

bpftrace 是 eBPF 的单行/脚本前端,语法类似 awk/DTrace,适合临时编写自定义探针(kprobe/uprobe/tracepoint)快速验证假设,比 BCC 更轻量灵活。当你需要临时看某个内核函数被调用多少次/耗时多少时首选。

前置与权限:需内核 ≥ 4.x(建议 ≥ 4.9)、bpftrace 包及内核头文件;运行需 root,或 CAP_BPF + CAP_PERFMON(内核 5.8+)。生产环境短脚本验证即可,避免长期挂载高开销探针。

bash 复制代码
# 安装
yum install bpftrace
apt install bpftrace

# 单行脚本示例

# 追踪 read 系统调用延迟
bpftrace -e 'tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read /@start[tid]/ { @ns = hist(nsecs - @start[tid]); delete(@start[tid]); }'

# 按进程统计系统调用次数
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

# 追踪 malloc 大小分布
bpftrace -e 'uprobe:/usr/lib64/libc.so.6:malloc { @bytes = hist(arg0); }'

# 追踪调度事件
bpftrace -e 'tracepoint:sched:sched_switch { @[args->prev_comm] = count(); }'

# 追踪 TCP 重传
bpftrace -e 'kprobe:tcp_retransmit_skb { printf("%s pid=%d\n", comm, pid); }'

# 生成火焰图
bpftrace -e 'profile:hz:99 { @[ustack] = count(); }' -c <command> -o out.bt
./FlameGraph/stackcollapse-bpftrace.pl out.bt > out.folded
./FlameGraph/flamegraph.pl out.folded > flame.svg

9.3 ftrace(内核函数追踪)

ftrace 是内核自带的函数追踪器,无需额外安装,通过 tracefs(/sys/kernel/debug/tracing)操作,可追踪指定函数、函数图、调度事件等。适合无 BCC/eBPF 环境下或需要内核函数级细节时(如调度、中断、唤醒路径)。

前置与权限:ftrace 随内核自带,无需额外安装,但需 tracefs 已挂载(通常 /sys/kernel/debug/tracing,依赖 debugfs 挂载,多数发行版默认开启);操作需 root。部分追踪器(如 function_graph)在低版本或特定内核配置下可能不可用,具体看 available_tracers。

bash 复制代码
cd /sys/kernel/debug/tracing

# 查看可用追踪器
cat available_tracers
# hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop

# 函数追踪
echo function > current_tracer
echo vfs_read > set_ftrace_filter
echo 1 > tracing_on
cat trace_pipe
echo 0 > tracing_on

# 函数图追踪(显示调用树和耗时)
echo function_graph > current_tracer
echo vfs_write > set_graph_function
echo 1 > tracing_on
cat trace
echo 0 > tracing_on

# 事件追踪
echo 1 > events/sched/sched_switch/enable
echo 1 > events/irq/enable
cat trace_pipe

# 使用 trace-cmd 简化操作
trace-cmd record -e sched_switch -e sched_wakeup sleep 5
trace-cmd report

9.4 SystemTap

SystemTap 是较早的内核动态追踪框架,用脚本在内核任意位置埋点,功能强大但依赖内核 debuginfo、易因版本不匹配失败。如今多被 eBPF/BCC 替代,但在特定发行版/老内核上仍有价值。

前置与权限:需 systemtap + systemtap-runtime,以及与当前运行内核完全一致的 kernel-devel 与 kernel-debuginfo(debuginfo 通常体积大、且每个内核版本一份)。版本或配置不匹配是最常见的失败原因------这是它被 eBPF 取代的主因。

bash 复制代码
# 安装
yum install systemtap systemtap-runtime

# 示例:追踪系统调用耗时
stap -e 'probe syscall.* { if (pid() == target()) printf("%s %d\n", name, gettimeofday_us()) }' -x <PID>

# 示例:I/O 调度延迟
stap /usr/share/systemtap/tapset/iostats.stp

9.5 火焰图全家桶

本节汇总各类火焰图(CPU、off-CPU、内存、I/O、eBPF 火焰图)的生成套路与适用场景,作为 3.4 与 9.x 的整合速查,帮助你针对不同类型瓶颈选对采样方式。

bash 复制代码
# CPU 火焰图(用户态 + 内核态)
perf record -F 99 -ag sleep 30
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > cpu.svg

# 内存分配火焰图
perf record -e 'kmem:kmalloc' -ag sleep 30
perf script | ./stackcollapse-perf.pl | ./flamegraph.pl --color=mem > mem.svg

# 阻塞火焰图(off-CPU)
# 使用 bcc offcputime
offcputime -df 30 > off.folded
./flamegraph.pl --color=io --title="Off-CPU" off.folded > offcpu.svg

# 差分火焰图
./difffolded.pl before.folded after.folded | ./flamegraph.pl > diff.svg

# Java 火焰图(async-profiler)
./profiler.sh -d 30 -f flame.html <PID>

# Go 火焰图
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30

9.6 容器环境性能分析

容器共享内核但受 cgroup 限制、有额外网络/存储层,排查思路与裸机不同(需进容器看 cgroup、用 cadvisor/node-exporter)。本节补充容器场景下的性能分析要点与常见坑。

bash 复制代码
# Docker 容器资源查看
docker stats --no-stream
docker top <container>

# 进入容器 netns 分析网络
nsenter -t $(docker inspect --format '{{.State.Pid}}' <container>) -n ss -tanp

# cgroup 限制查看
docker inspect <container> | grep -i "memory\|cpu\|blkio"

# Kubernetes Pod
kubectl top pod -n <ns>
kubectl top node
kubectl describe pod <pod> | grep -A5 "Limits\|Requests"

# 容器内 perf(需要 privileged 或 SYS_ADMIN)
docker run --privileged -v /usr/src:/usr/src ...

容器排障常见坑:① 资源上限由 cgroup 决定------容器内 free/top 看到的是宿主机视角,真实限额要看 cgroup(/sys/fs/cgroup/.../memory.max、cpu.max、io.max,见 8.6);② 容器内跑 perf/eBPF 需 CAP_BPF/CAP_PERFMON 或 --privileged,否则报权限错误;③ 网络多一层 CNI(flannel/calico 等),抓包要在正确 netns(nsenter -t -n);④ 存储多一层 CSI/overlay,I/O 延迟要区分容器层与底层设备(结合 5.x)。k8s 场景优先用 kubectl top + Prometheus/cAdvisor 看真实用量。


10. 内核参数调优

10.1 网络调优

本节给出网络子系统的关键调优项(缓冲区、连接回收、offload、队列),按先测后调、一次一项原则应用,目标是降低延迟、提升吞吐。

bash 复制代码
# /etc/sysctl.d/99-network-tuning.conf

# === TCP 缓冲区 ===
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# === 连接队列 ===
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 65535

# === TCP 连接复用 ===
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 2000000
net.ipv4.tcp_fin_timeout = 15

# === keepalive ===
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5

# === 拥塞控制 ===
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq    # bbr 需要 fq

# === 连接跟踪 ===
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 3600

# === 端口范围 ===
net.ipv4.ip_local_port_range = 1024 65535

# 生效
sysctl -p /etc/sysctl.d/99-network-tuning.conf

10.2 内存调优

内存调优围绕回收策略(swappiness)、脏页阈值、透明大页(THP)、slab 等展开。本节列出常用可调参数及其对性能的影响,强调先建立基线再调整。

bash 复制代码
# /etc/sysctl.d/99-memory-tuning.conf

# 减少 swap 使用
vm.swappiness = 1

# 脏页回写
vm.dirty_ratio = 40
vm.dirty_background_ratio = 10
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500

# 内存过量分配策略(1=总是允许,数据库常用)
vm.overcommit_memory = 1

# OOM 时杀进程而非 panic
vm.panic_on_oom = 0

# 透明大页(数据库通常关闭)
# 在 /etc/rc.local 或 systemd unit 中:
# echo never > /sys/kernel/mm/transparent_hugepage/enabled

# 页缓存回收倾向(值越大越倾向回收页缓存而非 slab)
vm.vfs_cache_pressure = 100

# min_free_kbytes:保留给内核的最小空闲内存
vm.min_free_kbytes = 1048576    # 1GB

sysctl -p /etc/sysctl.d/99-memory-tuning.conf

10.3 文件系统与 I/O 调优

I/O 调优涉及调度器选择、队列深度、文件系统挂载选项(noatime、日志模式)、readahead 等。本节给出针对不同负载(数据库/日志/大文件)的调优建议。

bash 复制代码
# 文件描述符限制
fs.file-max = 2097152
fs.nr_open = 2097152

# inotify 限制(大量文件监控时需要)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 8192

# AIO 限制
fs.aio-max-nr = 1048576

# 磁盘调度器(udev 规则)
# /etc/udev/rules.d/60-scheduler.rules
ACTION=="add|change", KERNEL=="sd[a-z]|nvme[0-9]*", ATTR{queue/scheduler}="mq-deadline"
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"

# 预读(顺序读多的场景增大)
blockdev --setra 4096 /dev/sda    # 2MB 预读

10.4 CPU 与调度调优

CPU 调优包括调度器策略、CPU 亲和性(taskset/numactl)、节能模式(cpufreq)、中断均衡(irqbalance)等。本节给出提升计算密集型或延迟敏感型业务性能的常见手段。

bash 复制代码
# CPU 频率策略
cpupower frequency-set -g performance

# 关闭 NUMA 自动平衡(数据库场景)
echo 0 > /proc/sys/kernel/numa_balancing

# 调度器参数
# 减少唤醒抢占延迟(对延迟敏感的应用)
echo 1000000 > /proc/sys/kernel/sched_min_granularity_ns
echo 1500000 > /proc/sys/kernel/sched_wakeup_granularity_ns

# 实时调度限制
echo -1 > /proc/sys/kernel/sched_rt_runtime_us    # 允许 RT 任务无限运行(慎用)

# 使用 tuned 一键配置
tuned-adm list
tuned-adm profile throughput-performance    # 吞吐优先
tuned-adm profile latency-performance       # 延迟优先
tuned-adm profile network-latency           # 网络低延迟

10.5 安全模块对性能的影响

SELinux、AppArmor 等安全模块在文件访问、exec 上做额外检查,会带来可测量的开销。本节说明如何评估其性能影响,以及在性能与安全的权衡中如何取舍。

bash 复制代码
# SELinux 状态
getenforce
# 排查时可临时设为 permissive
setenforce 0

# auditd 规则过多会影响性能
auditctl -l    # 查看规则
systemctl stop auditd    # 临时关闭测试

# AppArmor
aa-status

11. 性能监控体系搭建

11.1 指标采集层

可观测性体系的基础是采集。本节表格梳理指标采集层的常见组件(node-exporter、telegraf、collectd 等)与采集对象,作为监控落地的前置知识。

工具 用途 采集方式
node_exporter 系统指标 Prometheus pull
process_exporter 进程级指标 Prometheus pull
dcgm-exporter GPU 指标 Prometheus pull
smartctl_exporter 磁盘 SMART Prometheus pull
cAdvisor 容器指标 Prometheus pull
collectd 通用系统指标 push/pull
Telegraf 通用采集 push

11.2 告警规则示例(Prometheus)

告警是监控闭环的一环。本节给出基于 Prometheus 的实用告警规则示例(CPU、内存、磁盘、网络阈值),可直接套用或改写。

yaml 复制代码
groups:
  - name: linux_performance
    rules:
      - alert: HighCPULoad
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "CPU 使用率超过 90% 持续 10 分钟"

      - alert: HighIOWait
        expr: rate(node_cpu_seconds_total{mode="iowait"}[5m]) * 100 > 30
        for: 5m
        labels:
          severity: warning

      - alert: MemoryPressure
        expr: rate(node_pressure_memory_waiting_seconds_total[5m]) > 0
        for: 5m

      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1
        for: 5m
        labels:
          severity: critical

      - alert: HighNetworkErrors
        expr: rate(node_network_receive_errs_total[5m]) + rate(node_network_transmit_errs_total[5m]) > 10
        for: 5m

      - alert: SwapUsageHigh
        expr: (node_memory_SwapTotal_bytes - node_memory_SwapFree_bytes) / node_memory_SwapTotal_bytes > 0.5
        for: 10m

11.3 链路追踪与 APM

单看主机指标无法回答一次请求慢在哪个服务。链路追踪(tracing/APM,如 Jaeger、SkyWalking)还原请求调用链,本节说明其原理与在性能排查中的定位。

  • 分布式追踪: Jaeger / Zipkin / SkyWalking / OpenTelemetry
  • APM: Datadog / New Relic / Dynatrace / Elastic APM
  • 日志: ELK (Elasticsearch + Logstash + Kibana) / Loki + Grafana
  • Profiling 平台: Pyroscope / Parca / Datadog Continuous Profiler

11.4 Grafana 仪表盘推荐

Grafana 把采集到的指标可视化。本节推荐几套成熟的仪表盘模板(Node Exporter Full 等)与关键面板,帮助你快速搭建一眼看全系统的监控视图。

  • Node Exporter Full (ID: 1860)
  • Linux Performance Dashboard (ID: 14232)
  • Process Exporter (ID: 249)
  • NVIDIA DCGM (ID: 12239)

12. 经典案例实战

案例 1:CPU 100% 排查

现象: 某 Java 服务 CPU 持续 100%,响应超时。

bash 复制代码
# Step 1: 确认是哪个进程
top -bn1 | head -15
# 发现 java 进程 PID=23456 占用 380% CPU

# Step 2: 找到最耗 CPU 的线程
top -H -p 23456
# 发现 TID=23478 占用 99% CPU

# Step 3: 转为 16 进制
printf "%x\n" 23478
# 输出: 5bac

# Step 4: jstack 查看线程栈
jstack 23456 | grep -A 30 "nid=0x5bac"
# 发现死循环代码位置

# Step 5: 确认根因
# 某正则表达式在特定输入下产生灾难性回溯 (ReDoS)

案例 2:内存泄漏导致 OOM

现象: 服务运行数天后被 OOM Killer 杀死。

bash 复制代码
# Step 1: 确认 OOM
dmesg -T | grep -i "oom\|killed"
# [Mon Jan 15 03:22:11 2024] Out of memory: Kill process 12345 (myapp) score 850

# Step 2: 查看被杀时内存状态
dmesg -T | grep -B5 "killed process"
# 显示当时 MemFree 很低,某进程 RSS 异常大

# Step 3: 复盘------查看历史内存趋势
# 从 Prometheus/Grafana 查看该进程 RSS 曲线
# 发现每天增长约 500MB,不回收

# Step 4: 复现并定位
# 使用 jmap 分析堆
jmap -histo:live <PID> | head -30
jmap -dump:format=b,file=heap.hprof <PID>

# 使用 MAT (Memory Analyzer Tool) 分析
# 发现某 HashMap 只 put 不 remove,累积了 200 万对象

# Step 5: 修复
# 添加 TTL 过期机制或使用 WeakHashMap

案例 3:磁盘 I/O 延迟导致服务抖动

现象: 数据库每 5 分钟出现一次延迟尖刺。

bash 复制代码
# Step 1: 确认 I/O 延迟
iostat -xz 1 60
# 每 300 秒出现一次 await > 500ms,%util 100%

# Step 2: 查看是什么进程在写
iotop -oPa
# 发现是 backup 脚本在做全量 tar

# Step 3: 确认时间吻合
crontab -l
# 0 */5 * * * /opt/scripts/full_backup.sh

# Step 4: 解决方案
# 方案 A: 调整备份时间到业务低峰
# 方案 B: 使用 ionice 降低优先级
ionice -c2 -n7 tar czf ...
# 方案 C: 限速
pv -L 50m /data/db | tar czf backup.tar.gz -
# 方案 D: 改用增量备份

案例 4:网络 TIME_WAIT 堆积

现象: 短连接服务报 "Cannot assign requested address"。

bash 复制代码
# Step 1: 确认 TIME_WAIT 数量
ss -s
# TIME-WAIT: 280000

# Step 2: 查看端口范围
sysctl net.ipv4.ip_local_port_range
# 1024-65535,约 64000 个端口,但 TIME_WAIT 28 万远超

# Step 3: 确认是客户端还是服务端
ss -tan state time-wait | awk '{print $4}' | awk -F: '{print $NF}' | sort | uniq -c | sort -rn | head
# 大部分是本地端口(说明是本机作为客户端发起连接)

# Step 4: 解决
# 开启 tw_reuse(echo 写入 /proc 为临时生效、重启失效;持久化见下方 sysctl.d 配置)
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
# 扩大端口范围
echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range
# 减少 TIME_WAIT 时间
echo 15 > /proc/sys/net/ipv4/tcp_fin_timeout
# 根本方案:使用连接池

案例 5:上下文切换过高

现象: 系统 cs(上下文切换)达到 500 万次/秒,CPU %sy 30%。

bash 复制代码
# Step 1: 确认
vmstat 1
# cs 列持续 5000000+

# Step 2: 定位进程
pidstat -w 1 5 | sort -k4 -rn | head -10
# 发现某进程 nvcswch/s(非自愿切换)极高

# Step 3: 查看线程数
ps -T -p <PID> | wc -l
# 3000 个线程

# Step 4: 分析原因
# 线程数远超 CPU 核数(64核),调度竞争激烈
# 且线程间频繁锁竞争导致非自愿切换

# Step 5: 解决
# 减少线程数,使用线程池
# 或减少锁粒度

案例 6:容器内 DNS 解析慢

现象: Kubernetes Pod 内 HTTP 请求偶尔超时 5 秒。

bash 复制代码
# Step 1: 确认 DNS 延迟
time nslookup backend-service.default.svc.cluster.local
# 偶尔 5s+

# Step 2: 抓包分析
tcpdump -i eth0 -nn port 53
# 发现 DNS 查询发出后 5 秒才收到响应

# Step 3: 检查 conntrack
dmesg | grep conntrack
# "nf_conntrack: table full, dropping packet"
# 或 "insert_failed" 相关

# Step 4: 根因
# DNS 使用 UDP,conntrack 在高并发下 race condition 导致丢包
# 5 秒是 DNS 超时重试时间

# Step 5: 解决
# 方案 A: 增大 conntrack 表
sysctl -w net.netfilter.nf_conntrack_max=1048576
# 方案 B: Pod DNS 策略改为 NodeLocal DNSCache
# 方案 C: 应用使用 TCP DNS
# 方案 D: 使用 NodeLocal DNSCache (kube-dns 本地缓存)

案例 7:kswapd 导致 CPU 高

现象: 系统 %sy 高,perf 显示 kswapd0 占用大量 CPU。

bash 复制代码
# Step 1: 确认
top
# kswapd0 占用 30% CPU

# Step 2: 查看内存压力
cat /proc/pressure/memory
# some avg10=45.00 ...
free -h
# available 很低

sar -B 1 5
# pgscan_kswapd 很高

# Step 3: 分析原因
# 某进程申请了大量内存,触发频繁页回收
# 或页缓存被大量使用,回收扫描开销大

# Step 4: 解决
# 增加物理内存
# 限制进程内存(cgroup)
# 调整 vm.min_free_kbytes 增大
# 减少不必要的页缓存(如使用 O_DIRECT)

13. 性能排查速查表

13.1 按症状速查

遇到具体症状(卡顿、OOM、丢包...)不知从何下手?本节按症状→可能原因→首选工具的速查表,帮你秒级定位排查入口。

症状 首先检查 命令
系统慢/卡 负载、CPU、I/O wait uptime; vmstat 1; iostat -xz 1
CPU 高 哪个进程、用户态还是内核态 top; perf top; pidstat -u 1
内存不足 谁在用、是否泄漏 free -h; ps aux --sort=-%mem; smem
磁盘慢 IOPS、延迟、哪个进程 iostat -xz 1; iotop; blktrace
网络慢 丢包、重传、带宽 sar -n DEV; ss -s; nstat -az
进程 D 状态 I/O 卡住、NFS ps aux; cat /proc/<pid>/stack
OOM Kill 谁被杀、内存去哪了 dmesg; /proc/meminfo; cgroup
连接超时 连接队列、TIME_WAIT ss -s; nstat; tcpdump
中断风暴 哪个中断、是否集中 /proc/interrupts; mpstat -P ALL

排查决策流(钻取思路):先跑 60 秒法则(1.3)建立全局画像 → 用 USE 方法(1.1)定位瓶颈资源(CPU/内存/磁盘/网络)→ 进对应章节选概览工具确认现象 → 用进程级工具锁定罪魁进程 → 用深度追踪工具(perf/eBPF/strace)定位代码/内核级根因 → 调优(第 10 章)前后务必用基准(13.3)对比验证。症状→工具映射见上表,工具层级关系见 13.2。

13.2 工具矩阵

一张表汇总全文工具:用途、层级、是否需安装、适用场景。作为该用哪个工具的总索引。

资源 概览 进程级 深度追踪
CPU top, mpstat, vmstat pidstat -u, perf top perf record, flamegraph, bcc profile
内存 free, /proc/meminfo pmap, smem, /proc/pid/smaps memleak, bpftrace, kmemleak
磁盘 iostat, /proc/diskstats iotop, pidstat -d blktrace, biosnoop, biolatency
网络 sar -n, ip -s, ss nethogs, tcptop tcpretrans, tcpdump, bpftrace
调度 vmstat(r/b), runqlat pidstat -w perf sched, offcputime
文件 df, mount lsof, /proc/pid/fd fileslower, strace, opensnoop

13.3 性能测试基准命令

调优前后必须用基准测试验证效果。本节列出常用基准命令(cpu: sysbench、mem: stream、io: fio、net: iperf3),统一测试口径以便对比。

bash 复制代码
# CPU 基准
sysbench cpu --threads=64 --time=30 run

# 内存带宽
sysbench memory --threads=64 --time=30 run
stream    # STREAM benchmark

# 磁盘 IOPS
fio --name=randread --ioengine=libaio --direct=1 --bs=4k \
    --iodepth=32 --rw=randread --size=1G --runtime=60 \
    --filename=/dev/sdb --group_reporting

fio --name=seqwrite --ioengine=libaio --direct=1 --bs=128k \
    --iodepth=16 --rw=write --size=4G --runtime=60 \
    --filename=/data/testfile --group_reporting

# 网络带宽
iperf3 -c server -t 30 -P 4

# 网络延迟
sockperf ping-pong -i server -t 30

13.4 常用 sysctl 查看

sysctl 是内核运行时参数的入口。本节汇总最常用的一批 sysctl 查看命令(与 6.7/10.x 呼应),便于快速核对当前内核配置。

bash 复制代码
# 一键查看关键参数
sysctl -a 2>/dev/null | grep -E "^(net\.core\.(rmem|wmem|somaxconn|netdev_max)|net\.ipv4\.tcp_(rmem|wmem|max_syn|tw_reuse|fin_timeout|keepalive|congestion)|vm\.(swappiness|dirty_ratio|dirty_background|overcommit|min_free)|fs\.(file-max|nr_open)|kernel\.(sched|numa|hung_task|softlockup))"

13.5 性能分析思维导图

以一张思维导图收束全文,把方法论 → 工具 → 调优 → 监控串成体系,便于记忆与复盘。

复制代码
性能问题
├── 是变慢了还是不可用了?
│   ├── 变慢 → 找瓶颈资源 → USE 方法
│   └── 不可用 → dmesg / journalctl / OOM / 硬件故障
├── 是持续还是间歇?
│   ├── 持续 → 资源不足 / 配置问题
│   └── 间歇 → cron / GC / 备份 / 流量尖峰
├── 影响范围?
│   ├── 单进程 → 应用层分析
│   ├── 单容器 → cgroup 限制 / 邻居干扰
│   └── 全机 → 系统级资源竞争
└── 最近有什么变更?
    ├── 部署 / 配置变更 → 回滚验证
    ├── 内核升级 → 对比
    └── 硬件变更 → 驱动 / 固件

附录 A:推荐学习资源

资源 说明
《Systems Performance》- Brendan Gregg 系统性能圣经
《BPF Performance Tools》- Brendan Gregg eBPF 性能分析
《Linux Performance Optimization》- Christ
相关推荐
兵bing2 小时前
Docker Compose 配置文件归纳总结-千问
运维·docker·容器
dok122 小时前
Johannes 《Linux内核模块与设备驱动开发:编写Linux驱动程序》 (11)kmalloc 动态内存分配和struct file中的私有数据
linux·驱动开发·算法
INNOVIX稳石机器人3 小时前
从“存得下”到“管得活”:稳石四向穿梭车如何重塑密集仓储新逻辑?
大数据·运维
无足鸟ICT3 小时前
【RHCA+】if判断
linux
大魔王爱学习3 小时前
终端bash&zsh中实现基于前缀的历史命令搜索
linux·bash
2401_858286113 小时前
OS81.【Linux】基于环形队列的多生产者-多消费者模型
linux·运维·服务器·环形队列
X1A0RAN3 小时前
Jenkins Pipeline 变量打印指南
运维·servlet·jenkins
吴爃4 小时前
小微企业 SRE 稳定性建设(二):上线前 P0 验收项目
运维·可用性测试·稳定性·故障
月落归舟4 小时前
深入浅出:短信验证码登录场景下的 Nginx 负载均衡与 Session 共享
运维·nginx·负载均衡