服务器故障排查的系统化方法
Linux服务器运行中出现性能下降或服务异常时,排查方向不明确是最浪费时间的环节。系统化排查的核心是先定位瓶颈层级——CPU、内存、磁盘IO、网络四者中谁先饱和,再深入对应子系统。整个过程不需要复杂工具,vmstat、iostat、pidstat三个命令覆盖80%的日常故障定位场景。
CPU负载异常的快速定位
当系统响应变慢,第一步用uptime查看负载均值:
$ uptime
14:23:01 up 127 days, 3:15, 2 users, load average: 8.52, 6.31, 3.28
负载均值8.52远超CPU核心数(假设4核),说明进程排队严重。但高负载不代表CPU是瓶颈——IO等待也会推高负载。需要用vmstat区分:
$ 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
12 2 0 234512 89340 567890 0 0 523 12 4231 8932 35 8 12 45 0
8 3 0 198321 89120 568120 0 0 892 8 3987 9012 28 6 8 58 0
关键看wa列(IO Wait)和r列(运行队列)。wa值45%表示CPU大量时间在等待磁盘IO,r值12表示12个进程在等CPU时间片。此场景中wa是主因——磁盘IO阻塞导致CPU空闲等待,进而堆积进程队列。
如果wa接近0而r值高,说明是纯CPU瓶颈,用pidstat找出消耗CPU的进程:
$ pidstat -u 1 3
Linux 5.15.0-91-generic (server01) 08/03/2026 _x86_64_ (4 CPU)
02:14:01 PM UID PID %usr %system %guest %CPU CPU Command
02:14:02 PM 1000 2387 89.32 3.21 0.00 92.53 2 python3
02:14:02 PM 1000 3901 2.15 0.87 0.00 3.02 1 nginx
02:14:02 PM 0 1102 1.03 1.45 0.00 2.48 0 kubelet
PID 2387的python3进程占92.53% CPU。接下来用strace或perf进一步分析该进程的系统调用分布:
$ strace -c -p 2387
strace: Process 2387 attached
^Cstrace: Process 2387 detached
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
45.23 0.234512 12 19542 write
32.18 0.166789 8 20876 read
12.43 0.064523 15 4301 futex
9.16 0.047532 23 2071 12 openat
write和read调用占比77%,说明该进程在做大量IO操作。此时需确认它操作的文件路径:
$ ls -l /proc/2387/fd/ | head -20
cmd: python3 pid: 2387 fd: 0 -> /dev/pts/0
fd: 1 -> /dev/pts/0
fd: 3 -> /var/log/app/access.log
fd: 4 -> /data/cache/index.db
磁盘IO瓶颈深度定位
当vmstat显示wa值持续偏高,需要用iostat精确定位哪块磁盘、哪种IO类型是瓶颈:
$ iostat -xz 1 5
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await %util
sda 128.3 45.2 12.5 2.3 256.0 8.92 51.2 35.6 78.4 89.3
sdb 12.1 8.3 0.5 0.4 128.0 0.12 5.8 4.2 8.1 2.1
sda的%util达89.3%,avgqu-sz为8.92(队列深度接近9),await 51.2ms远超正常值(SSD应小于5ms,HDD应小于20ms)。w_await 78.4ms更说明写操作严重阻塞。
定位到具体磁盘后,需要找出哪些进程在产生IO。iotop可以实时显示进程级IO使用:
$ iotop -oP
Total DISK READ: 12.5 M/s | Total DISK WRITE: 2.3 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO COMMAND
2387 be/4 appuser 10.2 M/s 1.1 M/s 0.00 % 45.23 % python3 app.py
3901 be/4 www-data 0.8 M/s 0.3 M/s 0.00 % 3.12 % nginx: worker
1102 be/0 root 0.1 M/s 0.2 M/s 0.00 % 0.89 % kubelet
PID 2387的python3进程贡献了绝大部分读IO。结合strace的结论,该进程在密集读写/var/log/app/access.log和/data/cache/index.db。
针对这类日志密集写入场景,短期缓解方案包括:将日志输出改为异步缓冲写入、调整日志级别减少输出量、将日志文件挂载到tmpfs(如果不需要持久化)。长期方案则需要迁移到更高性能的存储介质或调整应用架构。
内存不足引发的问题诊断
内存问题通常表现为OOM Killer触发或swap使用量飙升。排查路径:
$ free -h
total used free shared buff/cache available
Mem: 15Gi 12Gi 1.2Gi 256Mi 2.8Gi 1.8Gi
Swap: 8Gi 3.2Gi 4.8Gi
available只有1.8Gi,swap已用3.2Gi——内存严重不足,系统大量换页。查看哪个进程占用最多内存:
$ ps aux --sort=-%mem | head -10
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
appuser 2387 2.3 45.2 8567324 7234560 ? Sl Jun12 234:56 python3 app.py
mysql 4501 1.8 22.1 4231567 3523456 ? Sl Jun12 189:23 mysqld
redis 5102 0.5 8.3 1234567 1345672 ? Ssl Jun12 56:78 redis-server
python3进程RSS达7.2GB占45.2%内存,mysqld占3.5GB。需要判断python3的内存增长是否合理:
$ cat /proc/2387/status | grep -E 'VmRSS|VmSize|VmSwap'
VmSize: 8567324 kB
VmRSS: 7234560 kB
VmSwap: 987654 kB
VmSwap接近1GB,说明该进程已被OOM部分换出。检查dmesg确认是否有OOM Killer记录:
$ dmesg | grep -i "oom" | tail -5
[123456.789] Out of memory: Kill process 7890 (java) score 450 or sacrifice child
[123456.790] Killed process 7890 (java) total-vm:4123MB, anon-rss:856MB
确有进程被OOM Killer杀死。解决方案按优先级:优化python3应用的内存使用(检查是否有内存泄漏)、调整mysqld缓冲池大小、或增加物理内存。临时措施可以调整vm.swappiness降低换页倾向:
# 临时降低swap倾向
$ sysctl vm.swappiness=10
# 永久生效
echo "vm.swappiness=10" >> /etc/sysctl.conf
网络延迟的排查技巧
当CPU、内存、磁盘都不是瓶颈,但服务响应仍慢时,排查网络层。用ss查看连接状态分布:
$ ss -s
Total: 12543
TCP: 23456 (estab 8900, closed 12000, orphaned 456, synrecv 23, timewait 11000)
TIME_WAIT 11000个连接,占TCP总量近一半。高TIME_WAIT通常意味着短连接频繁创建销毁。检查具体哪个端口:
$ ss -tn state time-wait | awk '{print $4}' | cut -d: -f2 | sort | uniq -c | sort -rn | head
4523 8080
2100 3306
1087 6379
8080端口TIME_WAIT最多,对应应用服务的出站连接。启用TCP连接复用可以缓解:
# 启用TIME_WAIT连接复用
$ sysctl net.ipv4.tcp_tw_reuse=1
# 减少TIME_WAIT超时时间
$ sysctl net.ipv4.tcp_fin_timeout=15
如果是延迟问题,用mtr持续追踪链路质量:
$ mtr --report --report-cycles 10 db.internal.example.com
HOST: server01 Loss% Snt Last Avg Best Wrst StDev
1. gateway 0.0% 10 0.3 0.4 0.2 0.8 0.2
2. switch-core 0.0% 10 0.5 0.6 0.4 1.2 0.3
3. db.internal 2.0% 10 1.2 1.5 1.0 3.2 0.8
第3跳有2%丢包和3.2ms最差延迟,可能存在网络拥塞或链路质量问题。结合sar -n DEV查看网卡的吞吐和错误计数,可以进一步确认是否到达带宽上限。
排查流程总结
完整排查路径遵循”四层递进”原则:先用uptime/vmstat确定瓶颈在CPU还是IO,再用pidstat/iostat定位到具体进程和磁盘,然后用strace/perf分析进程行为,最终用ss/mtr确认网络层是否有问题。每个层级都有对应的快速检测命令,关键是不跳步、不猜测,让数据驱动定位方向。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-gu-zhang-pai-cha-shi-zhan-cong-xi-tong-fu/