服务器故障排查
服务器故障排查
1️⃣ 负载检查(uptime)
定义:
CPU负载(cpu load)指的是单位时间内进程对系统产生的压力(单位时间内运行队列中的平均进程数)- 如果一个进程满足以下条件则其就会位于运行队列中:
- **可运行状态
R: **正在执行或者已经就绪的进程; - 不可中断睡眠状态
D: 等待磁盘IO、网络设备IO的进程;
- **可运行状态
- 下列进程不满足条件:
- 可中断睡眠
S: 比如在sleep(),或者阻塞等普通事件; - 僵尸进程
Z: 当前进程已经结束,但是父进程没有等待子进程; - 暂停进程
T: 当前进程被暂停了,比如接收到了Ctrl + C或者GDB
- 可中断睡眠
- 如果一个进程满足以下条件则其就会位于运行队列中:
命令:
uptime1
2
3$ uptime
// 1m 5m 15m
20:15:03 up 10 days, 3:42, 2 users, load average: 0.15, 0.20, 0.18load average:在单位时间内,有多少个进程在占用或者等待系统资源;
2️⃣ 内核日志检查(dmesg)
定义: 查看
Linux内核打印出来的消息(系统启动、磁盘信息、网卡信息、OOM等)命令:
dmesg1
$ dmesg | tail -n 200
- 查看最新内核日志消息
3️⃣ 实时查看系统当前资源占用情况(top)
定义: 常用来实时观察系统情况(
CPU利用率、Mem利用率、系统负载、运行/睡眠/僵尸进程数量)命令:
top1
2
3
4
5
6
7
8
9
10
11
12
13
14
15$ top
20:41:12 up 10 days, 3:26, 2 users, load average: 0.18, 0.25, 0.31
Tasks: 256 total, 1 running, 255 sleeping, 0 stopped, 0 zombie
%Cpu(s): 3.2 us, 1.1 sy, 0.0 ni, 95.1 id, 0.3 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem : 7820.4 total, 1240.6 free, 2650.1 used, 3929.7 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4620.5 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3251 mysql 20 0 1623548 412320 18240 S 6.3 5.1 32:11.54 mysqld
1820 root 20 0 512344 28420 10240 S 2.0 0.4 5:20.13 containerd
2418 root 20 0 1122336 65328 15872 S 1.7 0.8 18:42.66 java
936 root 20 0 189200 9424 7744 S 0.7 0.1 1:03.44 sshd
1142 root 20 0 69240 5100 3200 S 0.3 0.1 0:10.26 systemd
3310 www-data 20 0 245680 17480 6208 S 0.3 0.2 2:41.88 nginx
1 root 20 0 167920 12028 8408 S 0.0 0.1 3:15.20 systemd常用用法:
top -H -p pid:查看进程pid中所有线程情况1
2
3
4
5PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2418 root 20 0 1122336 65328 15872 S 1.7 0.8 18:42.66 java
2420 root 20 0 1122336 65328 15872 S 0.7 0.8 3:11.22 GC
2421 root 20 0 1122336 65328 15872 S 0.5 0.8 2:52.11 VM
2422 root 20 0 1122336 65328 15872 R 0.4 0.8 1:20.55 worker-1
4️⃣ 查看进程状态(pidstat)
- 定义: 经常用于检查
CPU使用率异常、上下文切换频繁 的问题; - 作用: 进一步定位是什么进程造成的,背后的具体原因是什么;
- 常用命令:
-p <pid>:监控指定进程;-t:显示进程信息;-u:显示CPU使用情况;-r:显示内存占用情况(kb虚拟内存/kb常驻内存);-d:显示I/O使用情况(磁盘读写速率);-w:显示上下文切换信息;
5️⃣ 查看某时刻的进程快照(ps)
定义:
ps用来查看 **某一时刻 **系统中的进程信息,本质上是一次性的静态快照。常用于查看进程是否存在、进程状态、父子进程关系、线程信息等。常用命令:
ps aux1
2
3
4
5
6
7
8
9
10$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 167920 12028 ? Ss Mar22 3:15 /sbin/init
root 936 0.1 0.1 189200 9424 ? Ss Mar22 1:03 /usr/sbin/sshd -D
root 1820 2.0 0.4 512344 28420 ? Ssl Mar22 5:20 /usr/bin/containerd
root 2418 1.7 0.8 1122336 65328 ? Sl Mar22 18:42 /usr/bin/java -jar app.jar
mysql 3251 6.3 5.1 1623548 412320 ? Sl Mar22 32:11 /usr/sbin/mysqld
www-data 3310 0.3 0.2 245680 17480 ? S Mar22 2:41 nginx: worker process
root 4521 0.0 0.0 11544 4020 pts/0 Ss 20:48 0:00 -bash
root 4630 0.0 0.0 12876 1120 pts/0 R+ 20:49 0:00 ps auxps -ef1
2
3
4
5
6
7
8
9
10
11$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Mar22 ? 00:00:03 /sbin/init
root 936 1 0 Mar22 ? 00:00:01 /usr/sbin/sshd -D
root 1142 1 0 Mar22 ? 00:00:00 /lib/systemd/systemd --user
root 1820 1 0 Mar22 ? 00:05:20 /usr/bin/containerd
root 2418 1 1 Mar22 ? 00:18:42 /usr/bin/java -jar app.jar
mysql 3251 1 6 Mar22 ? 00:32:11 /usr/sbin/mysqld
www-data 3310 1 0 Mar22 ? 00:02:41 nginx: worker process
root 4521 936 0 20:48 pts/0 00:00:00 -bash
root 4603 4521 0 20:49 pts/0 00:00:00 ps -ef
6️⃣ 查看磁盘 IO 统计(iostat)
定义:查看系统的 CPU 使用情况和磁盘
IO统计信息,常用于判断磁盘是否存在瓶颈。用法:
iostat -xz 11
2
3
4
5
6
7
8
9$ iostat -xz 1
Linux 5.15.0-92-generic (test-host) 03/22/2026 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
3.21 0.00 1.12 0.45 0.00 95.22
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s aqu-sz %util
sda 1.20 32.00 0.00 0.00 0.85 26.67 4.50 128.00 1.20 21.05 1.30 28.44 0.00 0.00 0.01 1.20
nvme0n1 15.30 512.00 0.00 0.00 2.10 33.46 22.40 1024.00 3.60 13.85 3.25 45.71 0.00 0.00 0.09 8.60
7️⃣ 查看哪些进程在做 IO
定义:
iotop用来实时查看哪些进程或线程正在产生磁盘IO用法:
iotop -oP-o:只显示当前正在做IO的进程-P:只显示进程,不展开线程
1
2
3
4
5
6
7
8$ sudo iotop -oP
Total DISK READ : 1.20 M/s | Total DISK WRITE : 2.40 M/s
Current DISK READ: 0.00 B/s | Current DISK WRITE: 1.00 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
3251 be/4 mysql 0.00 B/s 820.00 K/s 0.00 % 12.45 % mysqld
2418 be/4 root 0.00 B/s 120.00 K/s 0.00 % 2.31 % java -jar app.jar
1820 be/4 root 64.00 K/s 32.00 K/s 0.00 % 0.85 % containerd
8️⃣ 查看网络的情况
定义:
ss是Linux下用于查看socket统计信息和网络连接状态的命令用法:
ss -nltp1
2
3
4
5State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=936,fd=3))
LISTEN 0 80 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=3251,fd=21))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=3310,fd=6))
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=3310,fd=7))
9️⃣ 定位热点函数和分析调用栈(perf)
- 定义:
perf是Linux提供的性能分析工具,常用来- 定位热点函数
- 分析调用栈
- 排查
CPU高占用、锁竞争、上下文切换过多等性能问题。
- 用法:
perf top:实时查看热点函数perf record -F -g -p PID:对进程采样并记录调用栈perf report -i:分析采样结果
项目案例
CPU 利用率太高如何去排查?
1️⃣ 背景
为了说明 CPU 利用率过高时应该如何排查,直接拿 sylar 里的测试服务器做实验:
这个服务非常简单:
- 监听
0.0.0.0:8020 - 注册路由
/sylar/xx - 请求返回固定字符串
OK\n - 使用
sylar::IOManager iom(3),也就是3个调度线程
代码实例:
1 | sylar::http::HttpServer::ptr http_server( |
可以看到,这里几乎没有业务逻辑,所以如果压测时 CPU 仍然很高,说明瓶颈更可能在:
- 网络收发
HTTP解析与响应拼装- 协程调度与线程切换
- 系统调用频率过高
2️⃣ 复现
启动服务:
1 | ./root/workspace/sylar/bin/exe/my_http_server |
CPU 采样: 同时用 pidstat 观察进程和线程的 CPU
1 | pidstat -u -t -p <pid> 1 18 |
pidstat 结果
1 | 04:47:16 PM UID TGID TID %usr %system %guest %wait %CPU CPU Command |
%usr:CPU跑在 用户态 的比例,也就是应用自己的代码、C/C++运行库等;%system:CPU跑在 内核态 的比例,通常对应 系统调用 和 内核 帮它做的事;%wait:CPU等待I/O的时间百分比,例如 进程阻塞等待磁盘 或 网络响应。%CPU:总体CPU占用率- 解析:
- 死循环 或 空轮询,通常会看到:
- 没什么请求,
CPU还是高; - 某一个线程长期接近
100%; - 吞吐量上不去;
- 没什么请求,
- 死循环 或 空轮询,通常会看到:
重点
pidstat 里最关键的一点不是只有总 CPU,而是:
%usr%system
这说明什么?
user CPU高:用户态代码热点也不低system CPU高:系统调用和内核网络栈开销非常明显
也就是说,这个案例不能只盯着“是不是业务代码太重”,还要看:
send/recvacceptepoll- 锁与线程唤醒
选择分析
syscall侧工具:
strace命令:
strace -c -p <pid> -p <tid1> -p <tid2>结果:
1
2
3
4
5
6
7
8
9% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
70.96 6.635727 26 247345 sendto
26.24 2.454384 9 250234 2817 recvfrom
0.79 0.074287 14 4986 epoll_ctl
0.76 0.070971 10 6745 rt_sigprocmask
0.35 0.032592 11 2894 write
0.23 0.021266 18 1149 86 futex
0.20 0.018527 66 278 epoll_wait分析:
- 大部分时间花在
sendto/recvfrom epoll_ctl、epoll_wait也有开销futex说明线程同步不是完全没有成本
- 大部分时间花在
usercall工具:
perf命令:
perf record -F -g --call-graph -p <pid> --sleepperf report -i
结果:
call-graph1
2
3
4
5
6
7
8
9
10
11
12std::function<void ()>::operator()
-> sylar::http::HttpServer::handleClient
-> sylar::http::HttpSession::sendResponse 36.17%
-> sylar::Stream::writeFixSize 27.43%
-> sylar::Socket::send 27.17%
-> send / __x64_sys_sendto / tcp_sendmsg ...
-> sylar::http::HttpSession::recvRequest 32.34%
-> sylar::Socket::recv 15.59%
-> recv / __x64_sys_recvfrom / tcp_recvmsg ...
-> sylar::http::HttpResponse::dump 5.59%self(平铺视角)1
2
3
4
5
6
7
8
95.88% __lock_text_start
2.64% http_parser_execute
1.62% syscall_enter_from_user_mode
1.50% srso_alias_safe_ret
1.49% std::__cxx11::basic_string<...>::_M_data
1.10% malloc
1.07% __swapcontext
1.05% std::_Sp_counted_base<...>::_M_release
1.00% _int_free
3️⃣ 排查路径
- 通过
top/pidstat确认是哪个进程和线程CPU利用率高; - 分清
user CPU和system CPU;system高就先看strace -cuser高就继续用perf、火焰图、gdb看热点函数
- 回到代码定位到底是 空转、锁竞争,还是 网络与协议处理成本 高;
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 GYu的妙妙屋!
