服务器性能调优是每个后端工程师的必修课。面对线上 CPU 飙升、内存泄漏、磁盘 I/O 瓶颈等问题,如何系统性地定位和解决?本文将从方法论到实战,带你建立完整的性能调优知识框架。

一、性能调优的核心方法论

在动手之前,先建立正确的排查思路。推荐 USE 方法(Utilization, Saturation, Errors),这是 Brendan Gregg 提出的经典框架:

  • Utilization(利用率):资源忙碌的时间占比,比如 CPU 使用率 90%
  • Saturation(饱和度):资源的排队程度,比如运行队列长度、I/O 等待队列
  • Errors(错误):错误事件的数量,比如网卡丢包、磁盘坏块

面对任何性能问题,先回答三个问题:是什么资源出了问题?是利用率高还是饱和度大?有没有错误日志?

二、CPU 性能调优

2.1 快速定位 CPU 瓶颈

# 查看整体 CPU 使用情况
top -H  # 按线程查看,-H 参数非常关键

# 查看每个 CPU 核心的详细指标
mpstat -P ALL 1

# 实时采样进程的 CPU 使用和上下文切换
pidstat -w -u 1

这里有一个很多人忽略的细节:top 显示的是平均使用率,无法反映短时突刺。如果你怀疑有 CPU 毛刺,用 perf top 实时采样热点函数:

# 实时查看 CPU 热点函数(比 top 精确得多)
perf top -g

# 记录 30 秒的性能数据,生成火焰图
perf record -g -p $(pgrep your_app) -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

2.2 CPU 调度与进程优先级

Linux CFS(完全公平调度器)已经非常优秀了,但在某些场景下需要手动干预:

# 查看进程的调度策略和优先级
chrt -p $(pgrep your_app)

# 将关键进程设置为实时调度(慎用!可能饿死其他进程)
chrt -f -p 50 $(pgrep critical_task)

# 更安全的做法:调整 nice 值(-20 最高优先级,19 最低)
renice -n -10 -p $(pgrep important_task)

# 使用 cgroup 限制 CPU 使用(防止单个应用吃满 CPU)
cgcreate -g cpu:/limited_app
cgset -r cpu.cfs_quota_us=50000 /limited_app  # 限制为 50% CPU

实际案例:曾遇到一个 Node.js 服务间歇性响应超时,最后发现是 GC 停顿导致。通过 perf record -g -e 'syscalls:sys_enter_futex' 追踪到锁竞争,优化后 P99 延迟从 2s 降到 50ms。

三、内存管理优化

3.1 理解 Linux 内存布局

Linux 内存分成几层,理解这个架构是排查内存问题的前提:

  • 虚拟内存(VSS):进程看到的地址空间,包括未实际分配的
  • 常驻内存(RSS):物理内存中实际占用的部分
  • 共享内存:多个进程共享的 libc.so 等
  • Page Cache:文件系统的缓存,free 命令中的 buff/cache
  • Swap:被换出到磁盘的匿名页

3.2 内存泄漏排查

# 持续监控进程内存(观察 RSS 是否线性增长)
while true; do
  ps -o rss= -p $(pgrep your_app) | awk '{print strftime("%H:%M:%S"), $1/1024 "MB"}'
  sleep 5
done

# 用 pmap 看内存映射细节
pmap -x $(pgrep your_app) | sort -nrk3 | head -20

# 检查 /proc/meminfo 关键指标
grep -E '^(MemTotal|MemAvailable|Buffers|Cached|SwapTotal|SwapFree)' /proc/meminfo

如果 RSS 持续增长但无法定位,大概率是 堆内存碎片或第三方库内部缓存。这时候 valgrind --tool=massif 或者 jemalloc 的 profiling 功能会非常有用。

3.3 OOM Killer 与内存压力

# 查看 OOM 历史
dmesg | grep -i "out of memory"

# 查看 OOM 打分(数值越高越容易被 kill)
cat /proc/$(pgrep your_app)/oom_score

# 保护关键进程不被 OOM kill(-1000 表示完全保护)
echo -1000 > /proc/$(pgrep critical_app)/oom_score_adj

# 主动触发内存回收(比等 OOM 好)
echo 3 > /proc/sys/vm/drop_caches  # 释放 page cache

四、磁盘 I/O 优化

4.1 I/O 瓶颈定位

# 查看磁盘整体 I/O 情况
iostat -x 1

# 关注这些指标:
# await  - I/O 平均等待时间(>10ms 需要关注)
# svctm  - 实际服务时间
# %util  - 设备利用率(接近 100% 说明饱和)

# 定位具体是哪个进程在大量读写
iotop -o          # 只看有 I/O 活动的进程
pidstat -d 1      # 按进程统计 I/O

4.2 I/O 调度器选择

# 查看当前 I/O 调度器
cat /sys/block/sda/queue/scheduler
# 输出示例: [mq-deadline] kyber bfq none

# SSD 推荐 none(内核直接派发,减少 CPU 开销)
echo none > /sys/block/sda/queue/scheduler

# HDD 或混合负载推荐 mq-deadline 或 bfq
echo bfq > /sys/block/sda/queue/scheduler

# 对于 NVMe SSD,multiqueue 默认就是 none,无需调整

4.3 文件系统层面的优化

# 挂载时关闭访问时间记录(减少元数据写入)
mount -o remount,noatime /

# 对于数据库等高 IOPS 场景,考虑 XFS 或 ext4 + 特定参数
# XFS 在并发大文件读写上有优势
# ext4 + data=writeback 可以提升写入性能(牺牲一定的崩溃恢复安全性)

# 应用层优化:批量写入代替逐条写入
# 数据库场景:调整 innodb_flush_log_at_trx_commit(MySQL)
# 或者使用 WAL 模式(SQLite)

五、网络性能调优

# 查看网络吞吐和错误
sar -n DEV 1
ip -s link show eth0

# 检查 TCP 重传统计
netstat -s | grep -i retrans

# 查看 socket 队列溢出( backlog 不够大)
ss -lntp | grep -i send-q

# 调整内核网络参数
sysctl -w net.core.somaxconn=4096       # 增大监听队列
sysctl -w net.ipv4.tcp_tw_reuse=1       # 复用 TIME_WAIT 连接
sysctl -w net.ipv4.tcp_fastopen=3       # 启用 TCP Fast Open
sysctl -w net.core.rmem_max=134217728   # 增大接收缓冲区(128MB)
sysctl -w net.core.wmem_max=134217728   # 增大发送缓冲区

六、性能观测工具全景图

不同层级对应不同的观测工具,这里整理了一个完整的工具矩阵:

层级工具典型用途
应用层strace, ltrace追踪系统调用和库调用
语言运行时perf, gprof, pprofCPU profiling, 火焰图
系统调用strace -c, bpftrace统计系统调用耗时分布
内核perf, ftrace, eBPF内核函数追踪、动态埋点
硬件turbostat, PCMCPU 频率、功耗、缓存命中率

七、实战 Checklist

生产环境出问题时,按这个顺序快速排查:

  1. uptime — 先看负载(1min/5min/15min 平均负载)
  2. dmesg -T | tail -50 — 看内核日志有无 OOM、硬件错误
  3. vmstat 1 — 观察 CPU、内存、I/O 的整体变化趋势
  4. top -Hhtop — 定位高消耗进程
  5. iostat -x 1 — 判断是否磁盘 I/O 瓶颈
  6. netstat -s / ss -s — 排除网络层问题
  7. perf top / bpftrace — 深入分析热点

八、总结

性能调优不是玄学,是一套可以学习的工程方法:

  • 先建立基准:压测出系统极限指标,知道「正常」长什么样
  • 分层观测:从应用 → 运行时 → 系统调用 → 内核 → 硬件,逐层下钻
  • 一次只改一个变量:调参要有对照组,否则不知道是哪个改动生效
  • 监控先行:没有历史数据的调优是盲调,Prometheus + Grafana 是标配
  • eBPF 是未来:传统的 procfs 监控粒度和灵活性都不够,bpftrace 能做到零开销的动态追踪

希望这篇指南能帮你建立性能调优的系统思维。遇到具体问题,欢迎在评论区交流讨论。

本文首发于 清风小站,转载请注明出处。

本站所有原创文章采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。