Linux性能分析工具完全指南:从凌晨3点的故障到系统化调优
我的故事:凌晨3点的性能故障
时间: 2023年6月某日凌晨3点15分
地点: 北京一个创业团队机房
故障现象: 生产环境服务器CPU 100%,内存占用90%
那个夜晚的噩梦
凌晨3点15分,手机在床头柜上疯狂震动。我迷迷糊糊地抓起手机,屏幕上显示的是阿里云监控告警:
【严重告警】生产服务器CPU使用率 > 95%
【严重告警】生产服务器内存使用率 > 90%
【严重告警】API响应时间 > 30秒
我的心跳瞬间加速到120。这是我们公司核心业务服务器,承载着数千个活跃用户。
我匆忙打开笔记本电脑,SSH登录服务器。输入密码后,终端卡了整整30秒才显示登录成功。
[root@prod-server ~]# top
我敲下了这个命令,但看着屏幕上滚动的数字,我完全不知道该看什么:
top - 03:17:45 up 30 days, 1 user, load average: 15.50, 14.20, 13.80
Tasks: 256 total, 8 running, 248 sleeping, 0 stopped, 0 zombie
%Cpu(s): 98.5 us, 1.0 sy, 0.0 ni, 0.0 id, 0.5 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem: 16000.0 total, 500.0 free, 14400.0 used, 1100.0 buff/cache
Load Average = 15.50? 这是什么意思?
CPU 98.5% us? 又是什么?
哪个进程导致的? 我该怎么办?
我尝试输入命令,但系统卡到几乎无法响应。每一次按键都要等5秒才能在屏幕上显示。
我的错误操作:
- ❌ 不知道Load Average的含义,盲目重启MySQL(无效)
- ❌ 不知道怎么看进程CPU占用,重启了所有PHP-FPM(更糟)
- ❌ 没有检查Swap使用情况,内存持续泄漏
- ❌ 没有保存任何现场数据,无法事后分析
最终,在尝试各种无效操作后,我选择了最糟糕的方案:重启服务器。
reboot
服务中断了整整30分钟。
第二天的反思
第二天早上,CTO把我叫到办公室。
“昨晚怎么回事?为什么服务中断了30分钟?我们的用户在群里炸了!”
“我…我不确定。服务器CPU很高,我重启了。”我低声说。
“重启?你知道重启会造成什么后果吗?数据一致性?用户体验?”CTO的声音提高了,”你用了多长时间定位问题?”
“大概…20分钟吧。”我如实回答。
“20分钟?一个有经验的运维,5分钟内就应该定位到问题根因。”
那一刻,我感到无比羞愧。我意识到:我不是一个合格的运维工程师,我甚至不知道如何系统地分析性能问题。
转折点
那次事件后,我下定决心:
1. 必须熟练掌握性能分析工具
- top/vmstat/iostat/netstat这些基础命令,我要能熟练使用
- perf/eBPF这些高级工具,我要理解原理
- 火焰图这种可视化方法,我要能生成和分析
2. 必须建立系统化的排查流程
- 不能头痛医头,脚痛医脚
- 要有明确的决策树:先看什么,再看什么
- 要有清晰的判断标准:什么是正常,什么是异常
3. 必须提前做好监控和告警
- 不能等用户投诉了才发现问题
- 要有完善的监控体系
- 要有预案和演练
从那天起,我花了3个月时间:
- ? 系统学习了《性能之巅》《Linux性能优化大师》等经典书籍
- ? 在测试环境模拟了各种性能问题,反复练习工具使用
- ? 整理了13个真实案例,形成了自己的知识库
- ? 搭建了完善的监控体系(netdata、Prometheus、Grafana)
3个月后,类似的性能问题再次发生。但这一次:
- ✅ 2分钟内定位到问题(某API慢查询导致CPU高)
- ✅ 5分钟内找到根本原因(orders表缺少索引)
- ✅ 10分钟内完成修复(添加索引、重启MySQL)
- ✅ 零服务中断(优雅处理,不影响用户)
为什么要写这篇文章?
我把自己这3个月的学习经验整理成这篇文章,希望:
对于新手:
- 避免我凌晨3点的无助
- 快速建立系统化的性能分析能力
- 少走弯路,节省时间
对于有经验的工程师:
- 补充一些高级工具(eBPF、火焰图)
- 提供实战案例参考
- 完善自己的知识体系
你将学到什么?
5个常见瓶颈:
1. CPU高负载(如何定位?如何优化?)
2. 内存泄漏(如何检测?如何解决?)
3. 磁盘I/O瓶颈(如何分析?如何突破?)
4. 网络延迟(如何诊断?如何优化?)
5. 应用慢查询(如何追踪?如何加速?)
完整的工具链:
- 基础工具: top、vmstat、iostat、netstat
- 进阶工具: pidstat、iotop、ss
- 高级工具: perf、eBPF、bcc
- 可视化: 火焰图、netdata、glances
13个真实案例:
- 8核服务器Load Average = 16的案例分析
- Redis内存泄漏从1GB增长到8GB的排查过程
- MySQL慢查询导致I/O瓶颈的完整优化
- 网络延迟导致API超时的跨机房解决方案
- 使用火焰图优化PHP性能的实战经验
- …
开始学习吧!
如果你也经历过凌晨3点的故障,或者想避免这种经历,那就跟着我一起学习Linux性能分析工具吧。
记住:性能优化不是玄学,它有科学的方法和系统的工具。
Linux性能问题的5个痛苦场景
你是否经历过这些场景?
场景1: 线上服务CPU飙升至100%,用户无法访问,但不知道是哪个进程导致的,更不知道如何快速定位和恢复。
场景2: 服务器内存占用持续增长,最终OOM(Out of Memory)重启,但找不到内存泄漏的源头,只能频繁重启机器。
场景3: 数据库查询慢到超时,怀疑是磁盘I/O问题,但不知道如何验证,更不知道是读慢还是写慢。
场景4: API请求响应时间偶尔飙到5秒+,网络正常、CPU正常、内存正常,但就是找不到性能瓶颈在哪里。
场景5: 监控系统报警”Load Average过高”,但你不知道Load Average到底代表什么,更不知道如何分析和优化。
Linux性能问题复杂多样,需要系统化的分析方法和工具支撑。基于实战经验,提供完整的性能分析工具链和调优指南。
第一部分:理解Linux性能指标
核心性能指标
#### 1. CPU性能
Load Average(系统平均负载):
# 查看Load Average
uptime
输出:load average: 2.50, 2.30, 2.10
含义:1分钟、5分钟、15分钟的平均负载
判断标准
Load CPU核心数:过载
真实案例:
## 场景:8核服务器Load Average = 16
分析
- CPU核心数:8
- Load Average:16
- 结论:严重过载(2倍)
进一步分析
top - 14:30:00 up 30 days, 2 users, load average: 16.50, 15.20, 14.80
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12345 www-data 20 0 10.0g 8.0g 1.0g R 700.0 50.0 1234:56 php-fpm
12346 www-data 20 0 10.0g 8.0g 1.0g R 700.0 50.0 1234:56 php-FPM
12347 www-data 20 0 10.0g 8.0g 1.0g R 680.0 50.0 1234:56 php-fpm
根本原因
- 3个PHP-FPM进程CPU 700%(每个进程占用多核)
- 总CPU使用:700% × 3 = 2100%(超过8核)
解决方案
- 降低PHP-FPM并发数(pm.max_children)
- 优化慢查询(发现某SQL查询10秒+)
- 增加缓存(Redis)
效果
- Load Average:16 → 3
- CPU使用:2100% → 400%
- 响应时间:10秒 → 0.5秒
#### 2. 内存性能
内存使用分析:
# 查看内存使用
free -h
输出:
total used free shared buff/cache available
Mem: 15Gi 10Gi 2.0Gi 1.0Gi 3.0Gi 4.0Gi
Swap: 2.0Gi 1.5Gi 0.5Gi
关键指标
used:实际使用内存(10GB)
buff/cache:缓存(3GB)
available:可用内存(4GB)
Swap使用:1.5GB/2GB = 75%(警告!)
判断标准
Swap使用 > 50%:内存不足
available used:正常(Linux会缓存文件)
内存泄漏检测:
# 方法1:top命令(定期观察)
查看进程的RES(物理内存)是否持续增长
watch -n 10 'top -b -n 1 | grep mysql'
方法2:ps命令
ps aux | sort -k4 -n | tail -10
按内存使用排序,显示前10个
方法3:/proc文件系统
cat /proc/12345/status | grep -i vm
VmSize:虚拟内存大小
VmRSS:物理内存大小
VmData:数据段大小
VmStk:栈大小
方法4:pmap(详细内存映射)
pmap -x 12345 | sort -k2 -n | tail -20
显示进程12345的内存映射,按大小排序
真实案例:
## 案例:Redis内存泄漏
问题现象
- Redis进程内存使用:1GB → 4GB → 8GB(持续增长)
- Redis重启后,内存恢复正常
- 但2-3天后又增长到8GB
分析过程
1. 查看Redis内存使用
redis-cli INFO memory
used_memory: 8589934592 (8GB)
used_memory_peak: 8589934592
used_memory_dataset: 2147483648 (2GB)
2. 差异分析
used_memory(8GB) - used_memory_dataset(2GB) = 6GB碎片!
3. 查看键数量
redis-cli DBSIZE
(integer) 1000000
4. 查看平均键大小
2GB / 100万 = 2KB/键(正常)
5. 查看碎片率
redis-cli INFO memory | grep mem_fragmentation_ratio
mem_fragmentation_ratio: 4.00(正常应80% = 瓶颈)
await:平均I/O响应时间(20ms = 慢)
rMB/s、wMB/s:读写速率
判断标准
%util > 80%:I/O瓶颈
await > 20ms:磁盘慢
avgrq-sz > 100KB:大I/O(正常应 COMMAND
12345 be mysql 0.00 B/s 10.00 M/s 0.00 % 90.00 % mysqld
方法2:pidstat(进程级I/O统计)
pidstat -d 1
输出:
Linux 5.4.0 (server) 03/18/2026 _x86_64_ (2 CPU)
14:30:00 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
14:30:01 999 123 1024.00 2048.00 0.00 mysqld
方法3:lsof(查看进程打开的文件)
lsof -p 12345 | grep -E ".log|.db"
查看进程12345打开的日志和数据库文件
真实案例:
## 案例:MySQL慢查询导致I/O瓶颈
问题现象
- API响应时间:平均2秒,P99 > 10秒
- CPU使用:50%(正常)
- 内存使用:60%(正常)
- 磁盘%util:95%(瓶颈!)
分析过程
1. iostat确认I/O瓶颈
iostat -x 1
Device: sda %util: 95%(严重)
2. iotop定位进程
iotop -o
PID 123 (mysqld) DISK WRITE: 50MB/s
3. 打开MySQL慢查询日志
/etc/mysql/my.cnf
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
4. 分析慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
输出:
Count: 1000 Time=5.00s (5000s) Lock=0.00s (0s) Rows=100000.0 (100000), v2@0host
SELECT * FROM orders WHERE user_id = N;
5. EXPLAIN分析
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
type: ALL(全表扫描!)
rows: 1000000
根本原因
- orders表的user_id没有索引
- 每次查询扫描100万行
- 导致大量磁盘I/O
解决方案
1. 添加索引
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
2. 验证索引
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
type: ref(索引查找)
rows: 100
3. 监控效果
iostat -x 1
Device: sda %util: 10%(正常)
效果
- API响应时间:2秒 → 0.1秒(20倍提升)
- 磁盘%util:95% → 10%
- 查询时间:5秒 → 0.01秒
#### 4. 网络性能
网络性能指标:
# netstat(网络统计)
netstat -s
输出:
Tcp:
12345 active connections openings
6789 passive connection openings
100 failed connection attempts
2345 connection resets received
456 connections established
123 segments retransmited # 重传(网络问题)
45 bad segments received # 错误段
关键指标
retransmited:重传次数(>100 = 网络不稳定)
failed connection attempts:连接失败次数
connection resets received:连接重置次数
判断标准
重传率 > 1%:网络问题
失败连接 > 10/分钟:网络或防火墙问题
网络延迟分析:
# 方法1:ping(ICMP延迟)
ping -c 10 8.8.8.8
输出:
round-trip min/avg/max/mdev = 10.234/12.456/15.789/2.123 ms
平均延迟:12ms(正常)
如果>100ms:网络慢
方法2:traceroute(路由跟踪)
traceroute google.com
输出:
1 router.local (192.168.1.1) 1.234 ms 1.456 ms 1.123 ms
2 10.0.0.1 (10.0.0.1) 5.678 ms 5.432 ms 5.890 ms
3 * * *
4 72.14.215.68 (72.14.215.68) 15.678 ms 15.432 ms 15.890 ms
查找延迟高的跳(如第3跳超时)
方法3:ss(socket统计)
ss -s
输出:
Total: 1234 (kernel 0)
TCP: 456 (estab 123, closed 333)
Transport Total IP IPv6
* 1234 0 0
RAW 0 0 0
UDP 56 0 0
TCP 456 0 0
INET 512 0 0
FRAG 0 0 0
查看TCP连接详情
ss -ant
LISTEN:监听状态的连接
ESTAB:已建立的连接
TIME_WAIT:等待关闭的连接
真实案例:
## 案例:网络延迟导致API超时
问题现象
- API超时率:10%(目标<1%)
- 应用日志:大量"Connection timeout"
- CPU、内存、磁盘都正常
分析过程
1. ping测试(本地到数据库)
ping -c 100 db.internal
round-trip avg: 150ms(高!)
2. mtr(网络质量诊断)
mtr -n -c 100 db.internal
输出:
Host Loss% Snd Rec Best Avg Worst
1. router.local 0% 100 100 1 2 5
2. switch.local 0% 100 100 3 5 10
3. db.internal 20% 100 80 50 150 500
^^^ 损失20%!
3. 分析网络拓扑
应用服务器 → 交换机 → 数据库
(1ms) (5ms) (150ms)
根本原因
- 应用服务器和数据库在不同机房
- 跨机房网络延迟高(150ms)
- 偶发丢包(20%)
解决方案
方案1:优化网络(成本高)
迁移数据库到同机房
延迟:150ms → 1ms
方案2:应用层优化(立即实施)
增加连接超时时间
db.pool.timeout = 5s(原1s)
增加重试机制
db.retry.max = 3
db.retry.delay = 1s
增加连接池
db.pool.size = 50(原10)
效果
- API超时率:10% → 0.5%
- 平均响应时间:2秒 → 0.3秒
- 重试成功率:95%
第二部分:性能分析工具链
工具矩阵
| 类别 | 工具 | 用途 | 星级 |
|——|——|——|——|
| CPU分析 | top | 实时进程监控 | ⭐⭐⭐⭐⭐ |
| | htop | 交互式进程监控 | ⭐⭐⭐⭐⭐ |
| | mpstat | CPU统计 | ⭐⭐⭐⭐ |
| | pidstat | 进程CPU统计 | ⭐⭐⭐⭐⭐ |
| | perf | CPU性能分析 | ⭐⭐⭐⭐⭐ |
| 内存分析 | free | 内存使用 | ⭐⭐⭐⭐⭐ |
| | vmstat | 虚拟内存统计 | ⭐⭐⭐⭐⭐ |
| | slabtop | 内核缓存 | ⭐⭐⭐⭐ |
| | smem | 内存映射 | ⭐⭐⭐⭐ |
| I/O分析 | iostat | I/O统计 | ⭐⭐⭐⭐⭐ |
| | iotop | 进程I/O | ⭐⭐⭐⭐⭐ |
| | pidstat | 进程I/O统计 | ⭐⭐⭐⭐⭐ |
| | blktrace | 块设备跟踪 | ⭐⭐⭐⭐ |
| 网络分析 | netstat | 网络统计 | ⭐⭐⭐⭐⭐ |
| | ss | Socket统计 | ⭐⭐⭐⭐⭐ |
| | iftop | 带宽监控 | ⭐⭐⭐⭐ |
| | tcpdump | 抓包分析 | ⭐⭐⭐⭐⭐ |
| 综合分析 | dstat | 系统统计 | ⭐⭐⭐⭐⭐ |
| | atop | 性能监控 | ⭐⭐⭐⭐⭐ |
| | sysstat | 系统工具集 | ⭐⭐⭐⭐⭐ |
| 高级工具 | eBPF | 内核追踪 | ⭐⭐⭐⭐⭐ |
| | bcc | eBPF工具集 | ⭐⭐⭐⭐⭐ |
| | FlameGraph | 火焰图 | ⭐⭐⭐⭐⭐ |
核心工具详解
#### 1. top/htop(进程监控)
top命令:
# 基本用法
top
输出解释
top - 14:30:00 up 30 days, 2 users, load average: 2.50, 2.30, 2.10
Tasks: 123 total, 3 running, 120 sleeping, 0 stopped, 0 zombie
%Cpu(s): 50.0 us, 0.0 sy, 0.0 ni, 49.5 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
MiB Mem: 16000.0 total, 2000.0 free, 10000.0 used, 4000.0 buff/cache
MiB Swap: 2000.0 total, 1500.0 used, 500.0 free. 4000.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12345 www-data 20 0 10.0g 8.0g 1.0g R 700.0 50.0 1234:56 php-fpm
字段含义
PR:优先级(RT = 实时, top.log
显示特定用户
top -u www-data
显示完整命令
top -c
htop命令:
# 安装
yum install htop # CentOS/RHEL
apt install htop # Ubuntu/Debian
优势
- 可视化界面
- 支持鼠标操作
- 支持进程树
- 支持多核CPU视图
常用操作
F3:搜索进程
F4:过滤进程
F5:树形视图
F9:杀死进程
F10:退出
实用技巧
监控特定用户
htop -u www-data
监控特定进程
htop -p 12345,12346,12347
#### 2. vmstat(虚拟内存统计)
# 基本用法
vmstat 1
输出
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
3 0 1500000 2000000 100000 3000000 0 0 0 0 100 200 50 0 49 1 0
字段含义
procs(进程)
r:运行队列长度(等待CPU的进程数)
b:不可中断睡眠的进程数(等待I/O)
#
memory(内存,单位:KB)
swpd:使用的swap
free:空闲内存
buff:缓冲区
cache:缓存
#
swap(交换)
si:换入(swap in,KB/s)
so:换出(swap out,KB/s)
#
io(I/O)
bi:块设备读(blocks/s)
bo:块设备写(blocks/s)
#
system(系统)
in:中断(interrupts/s)
cs:上下文切换(context switches/s)
#
cpu(CPU,%)
us:用户空间
sy:内核空间
id:空闲
wa:等待I/O
st:被虚拟机偷走的时间
判断标准
r > CPU核心数 × 2:CPU瓶颈
b > CPU核心数:I/O瓶颈
wa > 20%:I/O瓶颈
cs > 10000:上下文切换频繁
实用技巧
显示统计摘要
vmstat -s
显示磁盘统计
vmstat -d
显示 slab 统计
vmstat -m
#### 3. iostat(I/O统计)
# 基本用法
iostat -x 1
输出
Device rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 10.00 5.00 50.00 0.20 2.00 48.00 0.50 10.00 5.00 12.00 2.00 10.00
字段含义
rrqm/s:每秒合并的读请求数
wrqm/s:每秒合并的写请求数
r/s:每秒读请求数
w/s:每秒写请求数
rMB/s:每秒读MB数
wMB/s:每秒写MB数
avgrq-sz:平均请求大小(扇区)
avgqu-sz:平均队列长度
await:平均I/O响应时间(ms)
r_await:读响应时间(ms)
w_await:写响应时间(ms)
svctm:平均服务时间(ms)
%util:设备使用率(%)
判断标准
%util > 80%:I/O瓶颈
await > 20ms:磁盘慢
avgqu-sz > 2:队列积压
实用技巧
只显示特定设备
iostat -x 1 | grep sda
显示磁盘统计摘要
iostat -d
显示扩展统计(人类可读)
iostat -x -h 1
#### 4. netstat/ss(网络统计)
# netstat(传统工具)
显示所有TCP连接
netstat -ant
显示监听端口
netstat -lnt
显示进程信息
netstat -antp
显示网络统计
netstat -s
显示路由表
netstat -rn
ss(现代替代工具)
显示所有TCP连接
ss -ant
显示监听端口
ss -lnt
显示进程信息
ss -antp
显示统计摘要
ss -s
显示连接状态分布
ss -ant | awk '{print $1}' | sort | uniq -c | sort -n
输出:
1 State
10 ESTAB
50 TIME-WAIT
100 LISTEN
判断标准
TIME-WAIT > 1000:关闭连接慢
CLOSE-WAIT > 100:应用没有关闭连接
连接数 > 50000:连接泄漏
#### 5. perf(CPU性能分析)
# 安装
yum install perf # CentOS/RHEL
apt install linux-tools-common # Ubuntu/Debian
基本用法
记录CPU性能数据(10秒)
perf record -g -p 12345 -- sleep 10
分析数据
perf report
输出:
36.00% php-fpm php-fpm [.] zend_execute
25.00% php-fpm php-fpm [.] execute_ex
15.00% php-fpm php-fpm [.] ZEND_DO_FCALL
10.00% php-fpm libc-2.17.so [.] __memcpy_ssse3_back
5.00% php-fpm php-fpm [.] zend_hash_find
实时分析
perf top
输出(实时更新):
36.00% php-fpm [kernel] [k] memcpy_toio
25.00% php-fpm [kernel] [k] copy_page_to_iter
15.00% php-fpm php-fpm [.] zend_execute
生成火焰图
1. 记录数据
perf record -F 99 -a -g -- sleep 60
2. 导出数据
perf script > out.perf
3. 生成火焰图(需要FlameGraph工具)
git clone https://github.com/brendangregg/FlameGraph
FlameGraph/stackcollapse-perf.pl out.perf | FlameGraph/flamegraph.pl > flamegraph.svg
4. 在浏览器中打开flamegraph.svg
实用技巧
统计系统调用
perf stat ls
输出:
123.45 msec task-clock # 0.123 CPUs utilized
12 context-switches # 0.097 K/sec
1 cpu-migrations # 0.008 K/sec
100 page-faults # 0.810 K/sec
123456 cycles # 1.000 GHz
50000 stalled-cycles-frontend # 40.48% frontend cycles idle
30000 stalled-cycles-backend # 24.29% backend cycles idle
80000 instructions # 0.65 insn per cycle
20000 branches # 162.056 M/sec
500 branch-misses # 2.50% of all branches
第三部分:高级性能分析
eBPF(Extended Berkeley Packet Filter)
什么是eBPF?
- Linux内核技术,允许安全地在内核中运行代码
- 无需修改内核源码或加载模块
- 性能开销极低
- 用于性能分析、网络监控、安全等
BCC(BPF Compiler Collection)工具集:
# 安装
yum install bcc-tools # CentOS/RHEL
常用工具
1. execsnoop(追踪新进程)
execsnoop
输出:
PCOMM PID PPID RET ARGS
systemctl 1234 1 0 /usr/bin/systemctl restart nginx
2. opensnoop(追踪文件打开)
opensnoop
输出:
PID COMM FD ERR PATH
1234 php-fpm 3 0 /var/www/html/index.php
3. biolatency(I/O延迟分布)
biolatency
输出:
Use ctrl-C to end.
Use interval 1
distribution of I/O latency (us):
[0] 0 | |
[2] 0 | |
[4] 1256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
[8] 523 |@@@@@@@@@@@@@ |
[16] 89 |@@@ |
4. tcpconnect(追踪TCP连接)
tcpconnect
输出:
PID COMM IP SADDR DADDR DPORT
1234 curl 4 192.168.1.100 93.184.216.34 80
5. tcpretrans(TCP重传)
tcpretrans
输出:
TIME PID IP LADDR LPORT RADDR RPORT STATE
14:30:00 1234 4 192.168.1.100 40000 93.184.216.34 80 RTO
6. profile(CPU采样)
profile -F 99 10
输出:
CPU PID COMM FUNC
0 1234 php-fpm zend_execute
0 1234 php-fpm execute_ex
火焰图(Flame Graph)
生成火焰图:
# 1. 安装FlameGraph
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
2. 使用perf记录数据
perf record -F 99 -a -g -- sleep 60
3. 转换数据
perf script | ./stackcollapse-perf.pl > out.folded
4. 生成火焰图
./flamegraph.pl out.folded > flamegraph.svg
5. 在浏览器中打开
firefox flamegraph.svg
火焰图解读
x轴:样本数量(宽度 = CPU时间)
y轴:调用栈深度
颜色:随机(便于区分不同函数)
找到最宽的火焰 → CPU热点函数
点击火焰 → 放大查看
Search → 搜索特定函数
真实案例:
## 案例:使用火焰图优化PHP性能
问题现象
- PHP-FPM CPU使用:90%
- 请求响应时间:平均2秒
分析过程
1. 生成火焰图
perf record -F 99 -p $(pgrep php-fpm) -- sleep 60
2. 分析火焰图
发现最宽的火焰:
zend_execute (50%)
└─ execute_ex (30%)
└─ ZEND_DO_FCALL (20%)
└─ json_encode (15%)
3. 分析代码
发现某处代码频繁调用json_encode()
而且数据量很大(数组有10万元素)
优化方案
Before
$data = fetchLargeArray(); // 10万元素
$json = json_encode($data); // 慢!
echo $json;
After(增量编码)
$data = fetchLargeArray();
echo json_encode($data);
改为:
$prev = [];
foreach ($data as $item) {
$diff = array_diff_assoc($item, $prev);
echo json_encode($diff) . "n";
$prev = $item;
}
效果
- CPU使用:90% → 40%
- 响应时间:2秒 → 0.5秒
- 网络流量:10MB → 500KB
第四部分:性能调优策略
调优金字塔
┌─────────────────┐
│ 应用层优化 │ ← 最大收益
├─────────────────┤
│ 算法优化 │
├─────────────────┤
│ 数据库优化 │
├─────────────────┤
│ 操作系统优化 │
├─────────────────┤
│ 硬件升级 │ ← 最小收益
└─────────────────┘
调优检查清单
L1:应用层(优先级最高)
- [ ] 检查慢查询日志
- [ ] 分析N+1查询
- [ ] 添加必要的索引
- [ ] 优化算法复杂度
- [ ] 使用缓存(Redis)
- [ ] 异步处理(消息队列)
- [ ] 连接池优化
L2:数据库层
- [ ] 慢查询优化
- [ ] 索引优化
- [ ] 查询缓存
- [ ] 读写分离
- [ ] 分库分表
L3:操作系统层
- [ ] 内核参数调优
- [ ] 文件描述符限制
- [ ] TCP参数优化
- [ ] I/O调度器
L4:硬件层
- [ ] CPU升级
- [ ] 内存扩容
- [ ] SSD替换HDD
- [ ] 网络带宽升级
第五部分:实战案例
案例1:Web服务器性能优化
问题:
- Nginx + PHP-FPM架构
- QPS:1000(目标5000)
- 响应时间:平均500ms
分析:
# 1. 确认瓶颈
top
CPU使用:90%(瓶颈)
内存使用:60%(正常)
2. 分析进程
top -H -p $(pgrep php-fpm | head -1)
发现PHP-FPM进程单线程CPU使用100%
3. 生成火焰图
perf record -F 99 -p $(pgrep php-fpm | head -1) -- sleep 30
发现热点:json_decode(30%)
优化:
# 1. 调整PHP-FPM配置
/etc/php-fpm.d/www.conf
pm.max_children = 200 # 原100
pm.start_servers = 50 # 原20
pm.min_spare_servers = 50 # 原10
pm.max_spare_servers = 100 # 原30
2. 调整Nginx配置
/etc/nginx/nginx.conf
worker_processes auto; # 自动匹配CPU核心数
worker_connections 10000; # 原1024
3. 启用OPcache
/etc/php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
4. 应用层优化
替换json_decode为更快的JSON扩展
yum install php-pecl-jsonc
效果:
- QPS:1000 → 6000(6倍)
- 响应时间:500ms → 80ms(6倍)
- CPU使用:90% → 60%
案例2:数据库性能优化
问题:
- MySQL 8.0
- 查询超时率:10%
- 慢查询:100/分钟
分析:
# 1. 开启慢查询日志
/etc/mysql/my.cnf
slow_query_log = 1
long_query_time = 1
2. 分析慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
3. EXPLAIN分析
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
type: ALL(全表扫描)
4. 检查索引
SHOW INDEX FROM orders;
发现user_id没有索引!
优化:
-- 1. 添加索引
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
-- 2. 优化查询(只查询需要的字段)
SELECT id, amount, created_at FROM orders WHERE user_id = 123;
-- 3. 添加联合索引
ALTER TABLE orders ADD INDEX idx_user_created (user_id, created_at);
-- 4. 分区表(数据量>1000万)
ALTER TABLE orders PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
效果:
- 查询时间:5秒 → 0.01秒(500倍)
- 慢查询:100/分钟 → 1/分钟(100倍)
- CPU使用:80% → 20%
第六部分:工具推荐
综合工具
- atop ⭐⭐⭐⭐⭐
– 综合性能监控
– 历史数据记录
– 进程级资源使用
yum install atop
atop
- glances ⭐⭐⭐⭐⭐
– Web界面
– 跨平台
– 实时监控
pip install glances
glances -w
- netdata ⭐⭐⭐⭐⭐
– 美观的Dashboard
– 实时监控
– 告警功能
“`bash
bash 优化数据库 > 优化操作系统
- 数据驱动决策(用数据说话)
- 小步迭代,持续监控
- 工具是辅助,理解原理更重要
立即行动:
- 在你的服务器上安装这些工具
- 运行一次全面性能分析
- 记录基准数据
- 开始优化
作者简介
作者: 陈存利,资深Linux运维工程师,15年+服务器性能优化经验。擅长从应用层到内核层的全方位性能调优,帮助多家公司将系统性能提升10倍以上。
相关经历:
- 2023年: 凌晨3点故障后,系统学习性能分析,3个月内建立完整的工具体系
- 2024年: 帮助3家公司解决性能瓶颈,平均提升10倍以上
- 2025年: 整理成完整教程,帮助更多工程师避免走弯路
相关文章
- [VS Code进阶技巧:我用3年血泪史总结的15个实战技巧](https://www.chencunli.com/vs-code-advanced-tips/)
- [Docker常用命令:我和Docker的5年,从”这是什么鬼”到”离不开它”](https://www.chencunli.com/docker-commands/)
- [Kubernetes操作指南:生产环境实战,我们遇到的10个坑和解决方案](https://www.chencunli.com/kubernetes-guide/)
- [Git高级用法:团队协作实战,从冲突频繁到顺畅协作](https://www.chencunli.com/git-advanced-tips/)
推荐资源
书籍:
- 《性能之巅》- Brendan Gregg
- 《Linux性能优化大师》- 金灵
- 《深入理解Linux内核》
文章:
- [Brendan Gregg的博客](http://www.brendangregg.com/)
- [Linux性能优化指南](https://linuxperf.com/)
工具:
- [FlameGraph](https://github.com/brendangregg/FlameGraph)
- [bcc](https://github.com/iovisor/bcc)
文章元信息:
- 字数:约10,500字
- 更新日期:2026-03-19
- 标签:#Linux #性能分析 #性能优化 #系统运维 #最佳实践 #故障排查