「零壹运维 · 零到壹,永不宕」
★服务器响应变慢,但看不出哪里出了问题——这是运维日常最让人抓狂的场景。CPU 飙高?内存泄漏?磁盘 IO 卡住?还是网络带宽打满?本文从实战角度出发,带你系统掌握 Linux 四大性能维度的瓶颈定位与调优方法,配合工具命令和优化手段,让每一次排查都有迹可循。
一、性能分析总体思路
1.1 性能排查的 60 秒法则
面对一台响应变慢的服务器,前 60 秒应该做什么?
# 1. 系统整体负载
uptime
# 2. 错误日志(最近 1 分钟内核错误)
dmesg | tail -20
# 3. vmstat 整体资源概览(1秒刷新,看3次)
vmstat 1 3
# 4. CPU 详细使用率
mpstat -P ALL 1 3
# 5. 进程级资源使用
pidstat 1 3
# 6. 磁盘 IO
iostat -xz 1 3
# 7. 内存使用
free -h
# 8. 网络统计
sar -n DEV 1 3
# 9. 进程快照
top -bn 1
# 10. 进程详细状态
ps aux --sort=-%cpu | head -20
1.2 性能分析四象限
高 CPU
│
CPU 密集 │ CPU + IO 双高
(计算型)│ (数据库/大文件处理)
─────────────────────────────
空闲等待 │ IO 密集
(正常/ │ (存储/日志写入)
配置问题)│
│
低 CPU
二、CPU 性能瓶颈定位与优化
2.1 CPU 核心指标
2.2 CPU 问题定位流程
# 第一步:查看负载和 CPU 使用率
top -b -n 1 | head -5
uptime
# 第二步:找出 CPU 使用率最高的进程
ps aux --sort=-%cpu | head -10
# 第三步:找出占用 CPU 最多的线程
top -H -p <pid>
# 或
ps -Lf <pid>
# 第四步:查看进程在做什么(系统调用分析)
strace -p <pid> -e trace=all -c 2>/dev/null
# 第五步:性能剖析(找热点函数)
perf top -p <pid>
# 或
perf record -g -p <pid> sleep 10
perf report
2.3 CPU 高负载常见原因与优化
场景一:us 高(用户态 CPU 高)
# 定位热点代码
perf top -p <pid>
# 常见原因:
# - 循环计算密集(算法效率低)
# - 大量正则匹配
# - JSON/XML 序列化反序列化
# - GC 频繁(Java/Go)
# 优化手段:
# - 算法优化,引入缓存
# - 多线程/协程并发
# - 升级 CPU 或水平扩展
场景二:sy 高(内核态 CPU 高)
# 查看系统调用频率
perf stat -p <pid> sleep 5
# 查看上下文切换
vmstat 1 5
# cs 列:context switches,持续 > 1万/秒 需关注
pidstat -w -p <pid> 1 5
# 常见原因:
# - 频繁系统调用(write/read 太小批量)
# - 频繁锁竞争导致上下文切换
# - 网络包处理量过大
# 优化手段:
# - 批量 IO,减少系统调用次数
# - 减小锁粒度,使用无锁数据结构
# - 提升网卡中断亲和性(IRQ affinity)
场景三:CPU Load 高但利用率低
# 查看 D 状态进程(不可中断睡眠,通常是 IO 等待)
ps aux | awk '$8 == "D" {print}'
# 查看等待 IO 的进程
cat /proc/<pid>/status | grep State
# 原因:进程卡在 IO 等待,负载高但 CPU 没在算
# 解决:优化磁盘 IO(见第四章)
2.4 CPU 绑定与亲和性优化
# 查看进程 CPU 亲和性
taskset -p <pid>
# 绑定进程到特定 CPU 核
taskset -cp 0,1 <pid>
# 启动时绑定
taskset -c 0,1 ./my-app
# NUMA 架构优化(多路服务器)
numactl --cpunodebind=0 --membind=0 ./my-app
# 查看 NUMA 节点信息
numastat
lscpu | grep NUMA
三、内存性能瓶颈定位与优化
3.1 内存核心指标
# 内存总览
free -h
# total used free shared buff/cache available
# Mem: 31Gi 8.2Gi 1.1Gi 312Mi 22Gi 22Gi
# Swap: 15Gi 0B 15Gi
| | |
|---|
used | | |
free | | |
buff/cache | | |
available | | 最关键指标 |
Swap used | | |
3.2 内存问题定位流程
# 第一步:确认内存是否不足
free -h
# available 低于总内存 10% → 内存压力大
# 第二步:找出内存占用最多的进程
ps aux --sort=-%mem | head -10
# 第三步:查看进程内存详情
cat /proc/<pid>/status | grep -E "VmRSS|VmSize|VmSwap"
# VmRSS:实际物理内存占用(最关键)
# VmSize:虚拟内存大小
# VmSwap:使用的 Swap
# 第四步:内存映射分析
pmap -x <pid> | sort -k3 -rn | head -20
# 第五步:内存泄漏检测
valgrind --leak-check=full ./my-app # C/C++ 程序
3.3 Swap 使用率高的排查
# 查看哪个进程在用 Swap
for i in /proc/*/status; do
awk '/VmSwap|Name/{printf $2 " " $3 "\n"}'$i
done 2>/dev/null | sort -k 2 -rn | head -20
# 查看 Swap 使用详情
swapon --show
cat /proc/swaps
# 如果内存充足但 Swap 被用,可以降低 swappiness
cat /proc/sys/vm/swappiness # 默认 60
echo 10 > /proc/sys/vm/swappiness # 临时调整
# 永久生效
echo"vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p
3.4 内存调优关键参数
# 查看所有内存相关内核参数
sysctl -a | grep vm
# 关键参数说明:
# vm.swappiness=10 减少 Swap 使用倾向(0=禁用,100=积极使用)
# vm.dirty_ratio=20 脏页占总内存比例超过此值触发强制刷盘
# vm.dirty_background_ratio=5 后台异步刷盘触发阈值
# vm.overcommit_memory=1 允许内存过量分配(容器环境常用)
# 透明大页(THP)关闭(数据库性能优化)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 永久关闭(加入 /etc/rc.local 或 grub 参数)
3.5 OOM 问题分析
# 查看 OOM Kill 日志
dmesg | grep -i "killed process"
grep -i "out of memory" /var/log/messages
journalctl -k | grep -i oom
# 查看进程 OOM score(越高越容易被杀)
cat /proc/<pid>/oom_score
cat /proc/<pid>/oom_score_adj
# 保护关键进程不被 OOM Kill
echo -1000 > /proc/<pid>/oom_score_adj
# 或永久配置(systemd 服务)
# OOMScoreAdjust=-1000
四、IO 性能瓶颈定位与优化
4.1 IO 核心指标
# iostat 详细输出
iostat -xz 1 3
# 关键指标:
# r/s, w/s 每秒读写次数(IOPS)
# rkB/s, wkB/s 每秒读写带宽
# await 平均 IO 等待时间(毫秒)<10ms 正常,>100ms 有问题
# %util 设备使用率(接近 100% 说明 IO 饱和)
# svctm 平均 IO 服务时间
4.2 IO 问题定位流程
# 第一步:确认是否有 IO 问题
iostat -xz 1 3
# %util 高 或 await 高 → IO 有问题
# 第二步:找出产生 IO 的进程
iotop -o -P
# -o:只显示有 IO 的进程
# -P:显示进程而不是线程
# 或用 pidstat
pidstat -d 1 5
# 第三步:找出操作的具体文件
lsof -p <pid> | grep -E "REG|DIR"
# 第四步:分析 IO 模式(顺序 vs 随机)
blktrace -d /dev/sda -o - | blkparse -i -
# 顺序 IO:吞吐量瓶颈
# 随机 IO:IOPS 瓶颈
4.3 IO 调优手段
文件系统层优化
# 查看文件系统挂载参数
mount | grep /data
# 常用优化挂载参数
# noatime:不更新文件访问时间(减少写操作)
# nodiratime:不更新目录访问时间
# barrier=0:禁用写屏障(需要 UPS 保护,SSD 可用)
# data=writeback:元数据模式,提升性能但掉电风险
# 示例(/etc/fstab)
/dev/sdb1 /data ext4 defaults,noatime,nodiratime 0 0
IO 调度器优化
# 查看当前 IO 调度器
cat /sys/block/sda/queue/scheduler
# [mq-deadline] kyber bfq none
# 推荐配置:
# HDD:mq-deadline 或 bfq(有公平性需求)
# SSD/NVMe:none(无队列调度,让硬件自己处理)
# 临时修改
echo none > /sys/block/nvme0n1/queue/scheduler
# 永久修改(udev 规则)
cat /etc/udev/rules.d/60-scheduler.rules
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="sd*", ATTR{queue/scheduler}="mq-deadline"
读缓存和预读优化
# 查看预读大小
blockdev --getra /dev/sda # 单位:512字节扇区
# 增大预读(顺序读场景)
blockdev --setra 4096 /dev/sda # 设为 2MB
# 文件系统缓存压力调整
echo 50 > /proc/sys/vm/vfs_cache_pressure # 默认 100,越小越倾向保留缓存
五、网络性能瓶颈定位与优化
5.1 网络核心指标
# 实时带宽使用
sar -n DEV 1 5
# rxkB/s 接收带宽,txkB/s 发送带宽
# 网络连接统计
ss -s
# 关注 TIME-WAIT 数量,过多会导致端口耗尽
# 网卡错误统计
ip -s link show eth0
# errors, dropped 持续增加 → 网卡或驱动问题
5.2 网络问题定位流程
# 第一步:确认带宽是否打满
sar -n DEV 1 3
# 或实时监控
iftop -i eth0
# 第二步:找出占用带宽最多的连接
nethogs eth0 # 按进程显示带宽
# 第三步:分析连接状态
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# TIME_WAIT 多 → 短连接太频繁
# CLOSE_WAIT 多 → 程序没有正确关闭连接
# 第四步:抓包分析
tcpdump -i eth0 -nn host 10.0.0.1 -w capture.pcap
# 用 Wireshark 分析 pcap 文件
5.3 TIME_WAIT 过多优化
# 查看 TIME_WAIT 数量
ss -tan | grep TIME-WAIT | wc -l
# 优化内核参数
cat >> /etc/sysctl.conf << EOF
# 开启 TIME_WAIT 快速回收(NAT 环境慎用)
net.ipv4.tcp_tw_reuse = 1
# 缩短 TIME_WAIT 超时(默认 60s)
net.ipv4.tcp_fin_timeout = 30
# 增大本地端口范围
net.ipv4.ip_local_port_range = 1024 65535
# 增大连接队列
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 65535
EOF
sysctl -p
5.4 高并发网络调优
# 查看当前网络参数
sysctl net.core.rmem_max
sysctl net.ipv4.tcp_rmem
# 高并发场景优化参数
cat >> /etc/sysctl.conf << EOF
# 增大 Socket 缓冲区
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# 开启 TCP BBR 拥塞控制(Linux 4.9+)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# 增大文件描述符限制
fs.file-max = 1000000
EOF
sysctl -p
# 用户级文件描述符限制
ulimit -n 65535
# 永久生效
echo"* soft nofile 65535" >> /etc/security/limits.conf
echo"* hard nofile 65535" >> /etc/security/limits.conf
5.5 开启 TCP BBR
# 检查内核版本(需要 4.9+)
uname -r
# 检查 BBR 是否可用
modprobe tcp_bbr
lsmod | grep bbr
# 开启 BBR
echo"net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo"net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p
# 验证
sysctl net.ipv4.tcp_congestion_control
# 输出:net.ipv4.tcp_congestion_control = bbr
六、完整性能排查 SOP
6.1 性能排查决策树
服务响应慢
│
├─ uptime → Load 高?
│ ├─ 是 → top 查 CPU
│ │ ├─ us 高 → 用户态热点,perf top 定位
│ │ ├─ sy 高 → 内核态,系统调用/锁竞争
│ │ ├─ wa 高 → IO 等待,iostat 定位
│ │ └─ D 状态进程多 → IO 卡住
│ └─ 否 → 继续往下
│
├─ free -h → 内存不足?
│ ├─ available 低 → ps 找内存大户
│ ├─ Swap 被用 → 调低 swappiness
│ └─ dmesg OOM → 增大内存或调 oom_score_adj
│
├─ iostat → IO 饱和?
│ ├─ %util > 90% → iotop 找 IO 进程
│ ├─ await > 100ms → 磁盘性能差或 IO 风暴
│ └─ 顺序/随机 → 调整调度器
│
└─ sar -n DEV → 网络打满?
├─ 带宽满 → nethogs 找进程
├─ TIME_WAIT 多 → 调 tcp_tw_reuse
└─ 丢包 → tcpdump 抓包分析
6.2 性能基线建立
# 建议定期采集以下基线数据(cron 每 5 分钟)
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BASEDIR=/var/log/perf_baseline
mkdir -p $BASEDIR
# CPU 负载
uptime >> $BASEDIR/load_$DATE.log
# 内存
free -h >> $BASEDIR/mem_$DATE.log
# IO
iostat -xz 1 3 >> $BASEDIR/io_$DATE.log
# 网络
sar -n DEV 1 3 >> $BASEDIR/net_$DATE.log
七、常用性能工具速查卡
| | |
|---|
| | top -H -p <pid> |
| | perf top -p <pid> |
| | mpstat -P ALL 1 3 |
| | pidstat -u 1 5 |
| | free -h |
| | vmstat 1 5 |
| | pmap -x <pid> |
| | iostat -xz 1 3 |
| | iotop -o -P |
| | blktrace -d /dev/sda |
| | sar -n DEV 1 3 |
| | ss -tan |
| | nethogs eth0 |
| | tcpdump -i eth0 -nn |
| | dstat -cdngy |
| | glances |
八、最佳实践
先监控,再优化:没有基线数据就动手调参,是盲目优化。先采集 7 天基线,再找异常。
一次只改一个参数:多个参数同时修改,出了问题无法判断原因。每次只调一个,观察效果。
内核参数临时先改,确认有效再持久化:先用 sysctl -w 临时生效,观察 24 小时,再写入 /etc/sysctl.conf。
性能和可靠性不能同时最优:关闭 barrier、开启 writeback 可以提升 IO 性能,但会增加断电数据损坏风险——做好权衡。
关注 available,不是 free:free -h 里 available 才是真正可用内存,free 只是完全空闲的部分。
TIME_WAIT 不一定是问题:大量 TIME_WAIT 是 TCP 协议正常行为,端口不耗尽就不用干预。CLOSE_WAIT 才是真正需要处理的。
生产变更必须有回滚方案:每次调参前记录原始值,写好回滚脚本,避免调优变"事故优"。
九、总结
性能调优没有银弹,只有方法论。找到瓶颈,理解原因,针对性优化,持续监控——这四步缺一不可。
★好的运维不是最快解决问题的人,而是最少出问题的人。性能调优的终点,是让系统在正常负载下平稳运行。