当登录到一台表现不佳的Linux系统中后,我们可以进行以下步骤来排查问题。
- 查看平均负载
- 查看系统日志
- 查看cpu饱和度
- 查看磁盘饱和度
- 查看内存饱和度
- 查看网络饱和度
- 跟踪进程
步骤1:查看平均负载
[root@VM-12-4-centos ~]# uptime
16:49:58 up 7 days, 19:49, 4 users, load average: 0.94, 0.66, 0.50
最后三个数字分别表示 1 / 5 / 15 分钟内的平均负载。通过对比它们的变化趋势,可以判断系统负载是在上升、下降还是保持稳定。
平均负载(Load Average)表示系统对 CPU 的总体需求,它同时包含:
- 正在 CPU 上运行的线程
- 正在等待 CPU 或处于不可中断状态(如 I/O)的线程
当 平均负载大于 CPU 数量 时,说明 CPU 资源已经不足,部分线程需要排队等待;
当 平均负载小于 CPU 数量 时,通常表示系统仍有余量,线程大多可以及时获得 CPU 执行。
举例来说,一个拥有 64 个 CPU 的系统:
- 平均负载为 128:表示平均每个 CPU 上 1 个线程在运行、1 个线程在等待
- 平均负载为 10:说明系统负载很低,还有大量 CPU 资源尚未被使用
因此,在评估平均负载时,必须先明确系统的 CPU 数量,可以通过 top 或 /proc/cpuinfo 获取,例如:
[root@VM-12-4-centos ~]# grep 'model name' /proc/cpuinfo | wc -l
当平均负载高于 CPU 数量 70% 的时候,你就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能。
但 70% 这个数字并不是绝对的,最推荐的方法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化趋势。当发现负载有明显升高趋势时,比如说负载翻倍了,你再去做分析和调查。
系统的平均负载值还是一个优秀指标,可以作为系统基准数据的一部分进行跟踪。如果知道您的系统在普通工作日的系统平均负载,而在有问题的同一天也处于同样的范围,这就是暗示您应该看看别的方面(如网络)来确定性能问题的原因。如果平均负载超出预期的正常水平,则表明您应该看看系统自身所运行的进程。
在linux上最好通过一些其他的指标料及CPU负载,例如vmstat和mpstat提供的一些数据。
步骤2:查看系统日志
[root@VM-12-4-centos ~]# dmesg |tail
[ 576.408049] atkbd serio0: Unknown key pressed (translated set 2, code 0x0 on isa0060/serio0).
[ 576.408749] atkbd serio0: Use 'setkeycodes 00 ' to make it known.
[ 576.738079] atkbd serio0: Unknown key released (translated set 2, code 0x0 on isa0060/serio0).
[ 576.738874] atkbd serio0: Use 'setkeycodes 00 ' to make it known.
[452528.220798] hrtimer: interrupt took 4380755 ns
[2505242.669943] conntrack: generic helper won't handle protocol 47. Please consider loading the specific helper module.
[3040185.594969] python3[26454]: segfault at a9 ip 0000000000549478 sp 00007ffcabffe870 error 4 in python3.7[400000+29e000]
[8552308.399053] TCP: request_sock_TCP: Possible SYN flooding on port 22. Sending cookies. Check SNMP counters.
[21887551.894806] AliSecGuard : 1818d2bba043a57cfe9bbe06fb701e2825c6e66d
[21887552.136283] AliSecGuard : 1818d2bba043a57cfe9bbe06fb701e2825c6e66d
这个命令显示过去10条系统日志,如果有的话,注意在这里寻找可能导致性能问题的错误。
我们还可以查看下/var/log/message 的内容。
步骤3:查看CPU饱和度
[root@VM-12-4-centos ~]# mpstat -P ALL 1
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:18:19 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:18:20 PM all 0.50 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.50
10:18:20 PM 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:18:20 PM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
10:18:20 PM 2 1.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.99
10:18:20 PM 3 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.00
10:18:20 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:18:21 PM all 12.06 0.00 2.51 0.00 0.00 0.00 0.00 0.00 0.00 85.43
10:18:21 PM 0 1.02 0.00 1.02 0.00 0.00 0.00 0.00 0.00 0.00 97.96
10:18:21 PM 1 13.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 85.00
10:18:21 PM 2 17.17 0.00 3.03 0.00 0.00 0.00 0.00 0.00 0.00 79.80
10:18:21 PM 3 16.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 0.00 80.00
这个命令将每个CPU分解到各个状态下的时间打印出来。选项-P ALL 用来打印每个CPU的报告,mpstat默认只打印系统级别的总结信息。
输出列如下:
- CPU:逻辑CPU ID或者all表示总结信息
- %usr:用户态时间
- %nice:以nice优先级运行的进程用户态时间
- %sys:系统态时间(内核)
- %iowait:I/O等待
- %irq:硬件中断CPU用量
- %sort:软件中断CPU用量
- %steal:耗费在服务其他租户的时间
- %guest:花在访客虚拟机的时间
- %idle:空闲
重要的有%usr,%sys,%idle。这些显示了每个CPU的用量以及用户态和内核态的时间比例。
这同样也能表明”热“CPU—那些跑到100%使用率(%usr+%sys)的CPU,而其他CPU并未跑满—–可能是由单线程应用程序的负载或者设备中断映射造成。
CPU花在执行用户态应用程序代码的时间称为用户态时间,而执行内核态代码的时间称为内核态时间。内核态时间包括了系统调用,内核线程和中断的时间。当在整个系统范围内进行测量时,用户态时间和内核态时间之比揭示了运行的负载类型。
计算密集的应用程序几乎会把大量的时间用在用户态代码上,用户态/内核态时间之比接近99/1。这类例子有图像处理,基因组学和数据分析。
I/O密集型的应用程序的系统调用频率较高,通过执行内核代码执行I/O操作。例如,一个进行网络I/O的Web服务器的用户态/内核态时间比大约为70/30。
这些数字依赖许多因素,只是用来表示预期的比例。
对于比较高的%iowait时间也要注意,可以使用磁盘I/O工具进一步分析。如果出现较高的%sys值,可以使用系统调用(syscall)跟踪和内核跟踪,以及CPU剖析手段进一步分析。我们可以用以下命令来查出是哪些进程占用了更多的CPU。
[root@VM-12-4-centos ~] pidstat 1
直接运行 pidstat 默认显示所有进程的 CPU 使用信息,等效于 `pidstat -u -p ALL。
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:19:21 PM UID PID %usr %system %guest %CPU CPU Command
10:19:22 PM 0 584 0.98 0.00 0.00 0.98 3 exe
10:19:22 PM 0 2730 1.96 0.00 0.00 1.96 1 AliYunDunMonito
10:19:22 PM 1009 24863 0.00 0.98 0.00 0.98 0 pidstat
10:19:22 PM UID PID %usr %system %guest %CPU CPU Command
10:19:23 PM 0 2350 0.00 1.00 0.00 1.00 0 AliYunDun
10:19:23 PM 0 2730 2.00 1.00 0.00 3.00 1 AliYunDunMonito
10:19:23 PM 1009 24863 1.00 2.00 0.00 3.00 0 pidstat
10:19:23 PM UID PID %usr %system %guest %CPU CPU Command
10:19:24 PM 0 584 0.00 1.00 0.00 1.00 3 exe
10:19:24 PM 0 2730 3.00 0.00 0.00 3.00 2 AliYunDunMonito
10:19:24 PM 0 3300 1.00 0.00 0.00 1.00 2 ilogtail
10:19:24 PM 1000 20259 1.00 0.00 0.00 1.00 3 java
10:19:24 PM 1009 24863 0.00 1.00 0.00 1.00 0 pidstat
10:19:24 PM UID PID %usr %system %guest %CPU CPU Command
10:19:25 PM 0 366 13.00 22.00 0.00 35.00 2 BT-Task
10:19:25 PM 0 2730 2.00 0.00 0.00 2.00 2 AliYunDunMonito
10:19:25 PM 1009 24863 0.00 1.00 0.00 1.00 0 pidstat
输出列如下:
- PID:进程ID
- %usr:进程在用户级(应用程序)执行时所使用的CPU百分比
- %system:进程在系统级执行时所使用的CPU百分比(内核)。
- %guest:进程在虚拟机(运行虚拟处理器)中消耗的CPU百分比。
- %CPU:进程使用的CPU时间的总百分比
- CPU:进程所在的CPU编号。
- Command:进程名
pidstat(1)命令按每个进程展示CPU的使用情况。top(1)命令虽然也很流行,但是pidstat(1) 默认支持滚动打印输出,这样可以采集到不同时间段的数据变化。
步骤4:查看磁盘饱和度
[root@VM-12-4-centos ~] iostat -xz 1
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
4.09 0.00 1.82 0.44 0.00 93.66
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 11.73 10.60 42.91 16.64 1182.58 151.87 44.81 0.05 0.88 3.42 4.43 0.33 1.98
avg-cpu: %user %nice %system %iowait %steal %idle
3.27 0.00 0.76 0.25 0.00 95.72
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 13.00 0.00 12.00 0.00 100.00 16.67 0.01 0.67 0.00 0.67 0.92 1.10
这个工具显示了存储设备的I/O指标。
要检查的列包括如下几个:
- r/s,w/s,rkB/s,wkB/s:这些是每秒向设备发送的读,写次数以及读,写字节数。可以用这些指标对业务负载画像。某些性能问题仅仅是因为超过了能够承受的最大负载导致的。
- await:I/O的平均响应时间,以毫秒为单位。这是应用需要承受的时间,它同时包含了I/O队列时间和服务时间。超过预期的平均响应时间,可看作设备已饱和或者设备层面有问题的表征。
- avgqu-sz: 设备请求队列的平均长度,比1大的值有可能是发生饱和的表征(不过对有些设备,尤其是对基于多块磁盘的虚拟设备来说,通常以并行方式处理请求)。
- %util:设备使用率,这是设备繁忙程度的百分比,显示了每秒设备开展实际工作的时间占比,不过它展示的并不是容量规划意义下的使用率,因为设备可以并行处理请求。大于60%的值通常会导致性能变差(可以通过await字段确认),不过这也取决于具体设备,接近100%的值通常代表了设备达到饱和状态。
我们可以使用下面的命令来查出哪些进程占用了更多的磁盘。
[root@VM-12-4-centos ~]pidstat -d
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:23:23 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
10:23:23 PM 1009 25780 0.00 0.00 0.00 bash
输出列如下:
- UID:用户ID
- PID:进程ID
- kB_rd/s: 每秒进程从磁盘读取的数据量 KB 单位
- kB_wr/s: 每秒进程向磁盘写的数据量 KB 单位
- kB_ccwr/s: 每秒进程向磁盘写入,但是被取消的数据量
- iodelay: 块I/O延迟
- Command: 进程名
步骤5:查看内存饱和度
[root@VM-12-4-centos ~]free -m
total used free shared buff/cache available
Mem: 7551 5502 168 93 1881 1658
Swap: 1024 312 712
这个输出显示了用MB作为单位的可用内存。检查可用内存(available)是否接近0,这个值显示了在系统中还有多少实际剩余内存可用,包括缓冲区和页缓存区。将一些内存用于缓存可以提升文件系统的性能。
[root@VM-12-4-centos ~] 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
2 0 320000 161364 191116 1742704 0 0 298 38 0 0 4 2 94 0 0
1 0 320000 163024 191124 1742744 0 0 0 432 3809 6990 2 2 96 1 0
0 0 320000 163148 191124 1742744 0 0 0 0 3683 6829 3 1 96 0 0
0 0 320000 163148 191132 1742748 0 0 4 104 3476 6764 1 0 99 0 0
0 0 320000 161612 191132 1742748 0 0 0 0 3736 7173 1 1 99 0 0
0 0 320000 161488 191132 1742752 0 0 0 128 3601 6853 0 0 99 0 0
0 0 320000 161340 191132 1742752 0 0 0 0 3432 6666 0 0 99 0 0
0 0 320000 161240 191132 1742756 0 0 0 0 3337 6532 0 0 100 0 0
0 0 320000 161240 191132 1742756 0 0 0 164 3440 6702 1 0 99 0 0
0 0 320000 161240 191132 1742756 0 0 0 0 3544 6853 1 0 99 0 0
输出如下,单位为KB:
- swap: 交换出的内存量
- free:空闲的可用内存
- buff:用于缓冲缓存的内存
- cache:用于页缓存的内存
- si:换入的内存(换页)
- so:换出的内存
如果si和so列一直非0,那么系统正存在内存压力并换页到交换设备或文件。我们可以使用pidstat工具来查出是哪些进程占用了更多的内存。
[root@VM-12-4-centos ~] pidstat -r 2 10
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:25:39 PM UID PID minflt/s majflt/s VSZ RSS %MEM Command
10:25:41 PM 0 584 2.97 0.00 1506924 24724 0.32 exe
10:25:41 PM 0 2730 8.91 0.00 264768 114204 1.48 AliYunDunMonito
10:25:41 PM 0 3300 1.49 0.00 338636 23164 0.30 ilogtail
10:25:41 PM 0 22792 0.50 0.00 690116 8128 0.11 aliyun-service
10:25:41 PM 1009 25545 349.01 0.00 108668 1340 0.02 pidstat
10:25:41 PM UID PID minflt/s majflt/s VSZ RSS %MEM Command
10:25:43 PM 0 530 1.00 0.00 743836 15720 0.20 hbrclient
10:25:43 PM 0 536 7.50 0.00 21672 452 0.01 irqbalance
10:25:43 PM 0 584 3.00 0.00 1506924 24724 0.32 exe
10:25:43 PM 0 2730 2.00 0.00 264768 114204 1.48 AliYunDunMonito
10:25:43 PM 1009 25545 315.50 0.00 108668 1432 0.02 pidstat
输出列如下:
- UID:用户ID
- PID:进程ID
- Minflt/s : 每秒次缺页错误次数 (minor page faults),虚拟内存地址映射成物理内存地址产生的 page fault 次数
- Majflt/s : 每秒主缺页错误次数 (major page faults), 虚拟内存地址映射成物理内存地址时,相应 page 在 swap 中
- VSZ virtual memory usage : 该进程使用的虚拟内存 KB 单位
- RSS : 该进程使用的物理内存 KB 单位
- %MEM : 内存使用率
- Command : 该进程的命令 task name
步骤6:查看网络饱和度
系统活动报告工具sar(1)可以观测当前活动并且能配置为保存和报告历史统计数据。
Linux版本用以下选项提供网络统计信息。
- -n DEV:网络接口统计信息。
- -n EDEV:网络接口错误。
- -n IP:IP 数据报统计信息。
- -n EIP:IP 错误统计信息。
- -n TCP:TCP 统计信息。
- -n ETCP:TCP 错误统计信息。
- -n SOCK:套接字使用。
[root@VM-12-4-centos ~] sar -n DEV 1
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:26:39 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
10:26:40 PM eth0 6.00 3.00 0.37 2.65 0.00 0.00 0.00
10:26:40 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
10:26:40 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
10:26:41 PM eth0 19.00 24.00 3.09 5.15 0.00 0.00 0.00
10:26:41 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
10:26:41 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
10:26:42 PM eth0 4.00 5.00 0.50 2.48 0.00 0.00 0.00
10:26:42 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
10:26:42 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
10:26:43 PM eth0 1.00 1.00 0.06 0.06 0.00 0.00 0.00
10:26:43 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
将不同的指标进行组合,sar(1)工具具有不同的运行模式。在这个例子中,我们使用它来看网络设备指标。通过接口吞吐量信息rxkB/s和txkB/s来检查是否有指标达到了上限。
[root@VM-12-4-centos ~] sar -n TCP,ETCP 1
Linux 3.10.0-1160.114.2.el7.x86_64 (izuf67tjsjwg8yv8bjejo1z) 01/11/2026 _x86_64_ (4 CPU)
10:27:11 PM active/s passive/s iseg/s oseg/s
10:27:12 PM 0.00 0.00 7.00 6.00
10:27:11 PM atmptf/s estres/s retrans/s isegerr/s orsts/s
10:27:12 PM 0.00 0.00 1.00 0.00 0.00
10:27:12 PM active/s passive/s iseg/s oseg/s
10:27:13 PM 0.00 0.00 7.00 7.00
10:27:12 PM atmptf/s estres/s retrans/s isegerr/s orsts/s
10:27:13 PM 1.00 0.00 1.00 0.00 0.00
10:27:13 PM active/s passive/s iseg/s oseg/s
10:27:14 PM 0.00 0.00 7.00 5.00
现在我们使用sar(1)工具来查看TCP指标和TCP错误信息,相关的字段包括如下几个:
- active/s:每秒本地发起的TCP连接的数量(通过调用connect()创建)
- passive/s:每秒远端发起的TCP连接的数量(通过调用accept()创建)
- retrans/s:每秒TCP重传的数量
主动和被动连接计数对业务负载画像很有用。重传则是网络或者远端主机有问题的征兆。
[root@VM-12-4-centos ~] netstat
基于使用的选项,netstat(8)命令能报告多种类型的网络统计数据,就像具有多种功能的组合工具。
选项介绍如下:
- (默认):列出连接的套接字。
- -a:列出所有套接字的信息。
- -s:网络栈统计信息。
- -i:网络接口信息。
- -r:列出路由表。
[root@VM-12-4-centos ~]# netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 874929364 0 0 0 1060892268 0 0 0 BMRU
lo 65536 145930374 0 0 0 145930374 0 0 0 LRU
数据列包括网络接口(Iface)、MTU,以及一系列接收(RX-)和传输(TX-)的指标。
- OK:成功传输的数据包。
- ERR:错误数据包。
- DRP:丢包。
- OVR:超限。
丢包和超限是网络接口饱和的指针。-c 连续模式能与-i 一并使用,每秒输出这些累积的计数器。它提供计算数据包速率的数据。
步骤7:跟踪进程
strace
strace常用来跟踪进程执行时的系统调用和所接收的信号。
在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。
strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。
-f表示跟踪子进程和子线程,-T表示显示系统调用的时长,-tt表示显示跟踪时间。
$ strace -f -T -tt -p pid
perf
perf利用Linux的trace特性,可以用于实时跟踪,统计event计数(perf stat);或者使用采样(perf record),报告(perf report|script|annotate)的使用方式进行诊断。
$ perf top -g -p pid

按方向键切换到 php-fpm,再按下回车键展开 php-fpm 的调用关系,你会发现,调用关系最终到了BF_crypt。接下来看下哪个地方调用了这个库,把对应的代码改下就可以了。
参考资料:
《性能之巅 洞悉系统,企业与云计算》
《BPF性能之巅》
《UNIX/Linux 系统管理技术手册》