Skip to content

Menu
Menu

Linux 性能问题排查思路

Posted on 2022年4月9日2023年12月26日 by zhezimi

当登录到一台表现不佳的Linux系统中后,我们可以进行以下步骤来排查问题。

  1. 查看平均负载
  2. 查看系统日志
  3. 查看cpu饱和度
  4. 查看磁盘饱和度
  5. 查看内存饱和度
  6. 查看网络饱和度
  7. 跟踪进程

步骤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分钟内的平均负载,通过比较这三个数字,你可以判断负载在15分钟内(或者其他时间段)是在上升,下降还是平稳。

平均负载代表了对CPU资源的需求,通过汇总正在运行的线程数(使用率)和正在排队等待运行的线程数(饱和度)计算得出。计算平均负载的一个新方法是把使用率加上线程调度器延时得出,而不是去取样队列长度,从而提高精度。

这个值的意义为,平均负载大于CPU数量表示CPU不足以服务线程,有些线程在等待,如果平均负载小于CPU数量,这(很有可能)代表还有一些余量,线程可以在它们想要的时候在CPU上运行。

举一个现代化的例子,一个有64颗CPU的系统的平均负载为128。这意味着平均每个CPU上有一个线程在运行,还有一个线程在等待。而同样的系统,如果平均负载为10,则代表还有很大的余量,在所有CPU跑满前还可以运行54个CPU消耗型线程。

平均负载最理想的情况是等于 CPU 个数。所以在评判平均负载时,首先你要知道系统有几个 CPU,这可以通过 top 命令或者从文件 /proc/cpuinfo 中读取,比如

[root@VM-12-4-centos ~]# grep ‘model name’ /proc/cpuinfo | wc -l

2

有了 CPU 个数,我们就可以判断出,当平均负载比 CPU 个数还大的时候,系统已经出现了过载。

当平均负载高于 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饱和度

mpstat -P ALL 1

这个命令将每个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剖析手段进一步分析。

pidstat 1 (查出是哪些进程占用了更多的CPU)

直接运行 pidstat 默认显示所有进程的 CPU 使用信息,等效于 `pidstat -u -p ALL。

输出列如下:

  • PID:进程ID
  • %usr:进程在用户级(应用程序)执行时所使用的CPU百分比
  • %system:进程在系统级执行时所使用的CPU百分比(内核)。
  • %guest:进程在虚拟机(运行虚拟处理器)中消耗的CPU百分比。
  • %CPU:进程使用的CPU时间的总百分比
  • CPU:进程所在的CPU编号。
  • Command:进程名

pidstat(1)命令按每个进程展示CPU的使用情况。top(1)命令虽然也很流行,但是pidstat(1) 默认支持滚动打印输出,这样可以采集到不同时间段的数据变化。

步骤4:查看磁盘饱和度

iostat -xz 1

这个工具显示了存储设备的I/O指标。

要检查的列包括如下几个:

  • r/s,w/s,rkB/s,wkB/s:这些是每秒向设备发送的读,写次数以及读,写字节数。可以用这些指标对业务负载画像。某些性能问题仅仅是因为超过了能够承受的最大负载导致的。
  • await:I/O的平均响应时间,以毫秒为单位。这是应用需要承受的时间,它同时包含了I/O队列时间和服务时间。超过预期的平均响应时间,可看作设备已饱和或者设备层面有问题的表征。
  • avgqu-sz: 设备请求队列的平均长度,比1大的值有可能是发生饱和的表征(不过对有些设备,尤其是对基于多块磁盘的虚拟设备来说,通常以并行方式处理请求)。
  • %util:设备使用率,这是设备繁忙程度的百分比,显示了每秒设备开展实际工作的时间占比,不过它展示的并不是容量规划意义下的使用率,因为设备可以并行处理请求。大于60%的值通常会导致性能变差(可以通过await字段确认),不过这也取决于具体设备,接近100%的值通常代表了设备达到饱和状态。

pidstat -d (查出是哪些进程占用了更多的磁盘)

输出列如下:

  • UID:用户ID
  • PID:进程ID
  • kB_rd/s: 每秒进程从磁盘读取的数据量 KB 单位
  • kB_wr/s: 每秒进程向磁盘写的数据量 KB 单位
  • kB_ccwr/s: 每秒进程向磁盘写入,但是被取消的数据量
  • iodelay: 块I/O延迟
  • Command: 进程名

步骤5:查看内存饱和度

free -m

这个输出显示了用MB作为单位的可用内存。检查可用内存(available)是否接近0,这个值显示了在系统中还有多少实际剩余内存可用,包括缓冲区和页缓存区。将一些内存用于缓存可以提升文件系统的性能。

vmstat 1

输出如下,单位为KB:

  • swap: 交换出的内存量
  • free:空闲的可用内存
  • buff:用于缓冲缓存的内存
  • cache:用于页缓存的内存
  • si:换入的内存(换页)
  • so:换出的内存

如果si和so列一直非0,那么系统正存在内存压力并换页到交换设备或文件。我们可以使用pidstat工具来查看具体是什么在消耗内存。

pidstat -r 2 10 (查出是哪些进程占用了更多的内存)

输出列如下:

  • 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:套接字使用。

sar -n DEV 1

将不同的指标进行组合,sar(1)工具具有不同的运行模式。在这个例子中,我们使用它来看网络设备指标。通过接口吞吐量信息rxkB/s和txkB/s来检查是否有指标达到了上限。

sar -n TCP,ETCP 1

现在我们使用sar(1)工具来查看TCP指标和TCP错误信息,相关的字段包括如下几个:

  • active/s:每秒本地发起的TCP连接的数量(通过调用connect()创建)
  • passive/s:每秒远端发起的TCP连接的数量(通过调用accept()创建)
  • retrans/s:每秒TCP重传的数量

主动和被动连接计数对业务负载画像很有用。重传则是网络或者远端主机有问题的征兆。

netstat

基于使用的选项,netstat(8)命令能报告多种类型的网络统计数据,就像具有多种功能的组合工具。

选项介绍如下:

  • (默认):列出连接的套接字。
  • -a:列出所有套接字的信息。
  • -s:网络栈统计信息。
  • -i:网络接口信息。
  • -r:列出路由表。

[root@VM-12-4-centos ~]# netstat -i

数据列包括网络接口(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 系统管理技术手册》

https://man7.org/linux/man-pages/man1/perf-top.1.html

相关文章

  • 排查网络故障常用命令

  • 网络I/O模型

  • grep

  • 《shell脚本攻略》笔记

  • vim常规使用

发表评论 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

近期文章

  • 排查网络故障常用命令
  • PHP-FPM异常问题
  • RabbitMQ 1:介绍
  • 观察者模式
  • 装饰者模式

近期评论

没有评论可显示。

分类

  • cdn
  • css
  • docker
  • git
  • http
  • javascript
  • linux
  • mysql
  • nginx
  • php
  • RabbitMQ
  • 代码规范
  • 性能
  • 正则表达式
  • 网络协议
  • 设计模式
© 2025 | Powered by Minimalist Blog WordPress Theme