Linux CPU性能监控教程
下面将提到我们将要讨论的事情。
- 监控系统性能
- 找到问题的根本原因
- 应用可能的修复程序来解决问题。
我非常确定,大多数有经验的系统管理员和新手都知道被称为“ top”的命令。
Top命令可用于获取正在运行的系统的当前状态。
Top命令显示服务器的繁忙程度。
最好记录一下系统的正常统计数据,以便我们可以将其与瓶颈期间测得的结果进行比较。
top - 00:56:55 up 1 min, 2 users, load average: 0.15, 0.11, 0.05 Tasks: 74 total, 1 running, 73 sleeping, 0 stopped, 0 zombie Cpu(s): 0.3%us, 0.3%sy, 0.0%ni, 99.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 499148k total, 229116k used, 270032k free, 27520k buffers Swap: 522236k total, 0k used, 522236k free, 67244k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 996 ubuntu 20 0 73440 1676 888 S 0.3 0.3 0:00.06 sshd 1162 root 20 0 17336 1248 944 R 0.3 0.3 0:00.03 top 1 root 20 0 24200 2204 1360 S 0.0 0.4 0:02.06 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root 20 0 0 0 0 S 0.0 0.0 0:00.34 ksoftirqd/0 4 root 20 0 0 0 0 S 0.0 0.0 0:00.06 kworker/0:0 5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H 6 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/u:0 7 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/u:0H 8 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 9 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh 10 root 20 0 0 0 0 S 0.0 0.0 0:00.18 rcu_sched 11 root RT 0 0 0 0 S 0.0 0.0 0:00.00 watchdog/0 12 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset
上面显示的是正常系统的顶部命令输出。
输出的第一行为我们提供CPU的最后十五分钟统计信息。
它告诉我们3个不同的CPU负载值。
它们是最后一分钟,最后5分钟,最后15分钟(这些是负载平均值。
)。
如今,通常使用多核处理器来获得更好的处理能力。
这些天很少使用单个核心处理器。
但是从最高输出中了解的重要一点是,它只关心系统,而不关心核心。
如果我们具有双四核处理器,则需要将这三个平均值中的每一个除以8.
因此,如果双四核处理器在最后一分钟的平均负载为8,则正确的值为8/8 = 1.
现在,请注意以下事实:显示的平均负载是系统的,而不是cpu的。
即使cpu不执行任何操作,也始终可能有1.0的负载。
当cpu等待I/O时,这种情况是正常的。
监视负载时要了解的一点是,当负载平均值比正常值高时,它并不总是不好的。
这取决于系统上运行的进程的类型。
如果该进程占用大量CPU,则其他进程必须等待...但是如果该进程属于I/O密集型,则在I/O等待时间内(CPU等待输入/输出操作完成的时间) ),CPU可以处理其他进程。
因此,在得出有关系统负载的结论时,系统上运行的那种进程起着主要作用。
root@ubuntu2:~# nproc 1
上面显示的nproc命令将给出linux系统上的cpu内核数。
由于top命令仅向我们提供系统上所有cpu内核的摘要,因此最好将top的平均值除以nproc输出,以获得系统负载的准确值。
我们还可以使用顶部命令控制台获取每个cpu内核的详细信息。
按1查看每个核心统计信息。
示例输出如下所示。
top - 02:58:48 up 94 days, 12:15, 1 user, load average: 0.31, 0.29, 0.24 Tasks: 173 total, 1 running, 172 sleeping, 0 stopped, 0 zombie Cpu0 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu1 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu2 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu3 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu4 : 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu5 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu6 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Cpu7 : 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1011048k total, 949720k used, 61328k free, 9176k buffers Swap: 524284k total, 98804k used, 425480k free, 103884k cached
上面的输出中显示了不同的值。
让我们看看它们各自的含义。
- us:这显示了由普通用户运行的进程引起的cpu工作量。换句话说,这些是应用程序引起的负载。
- sy:这表示系统创建的负载。意味着这些大多数情况下都是由Linux内核执行的。通常,它保持较低状态,但是对于涉及内核的某些任务而言,它会变得较高。
- ni:这是指以修改好的值运行的进程数。如果我们不熟悉漂亮的值,请参考以下文章。 \
阅读:Linux中的流程优先级和不错的价值
- id:这表示CPU不执行任何操作所花费的时间。较高的id值表示CPU大部分时间处于空闲状态
- wa:CPU等待I/O操作完成的时间。
- ha:这是指硬件中断。当我们具有较高的磁盘使用率或者较高的网络使用率时,此值会很高。
- si:这些是由软件创建的中断。这些值通常保持很低。
- st:这与系统上运行的虚拟机有关。当虚拟机需要CPU时,通常从主机上获取它。如果服务器上运行的虚拟机太多,并且此st值更高,则最好拆除一些虚拟主机。
这些天服务器使用的大多数处理器必须一次处理多个进程。
由于一个处理器(一个处理器核心)一次只能做一件事,因此处理器必须将那些需要运行的进程排队。
下面显示的是top命令的前几行。
top - 15:08:41 up 95 days, 25 min, 1 user, load average: 7.12, 6.50, 5.40 Tasks: 172 total, 2 running, 170 sleeping, 0 stopped, 0 zombie Cpu(s): 3.9%us, 0.2%sy, 0.0%ni, 95.8%id, 0.1%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1011048k total, 980280k used, 30768k free, 10016k buffers Swap: 524284k total, 103676k used, 420608k free, 130100k cached
我们确实讨论了一些有关平均负载的东西。
好吧,尽管一开始似乎很容易理解它在过去一分钟,五分钟和十五分钟内服务器的平均负载,但是了解了解获得该负载平均值的几个概念确实很有帮助。
主要原因是因为仅通过查看数字就很难判断出什么值是一个令人震惊的值和什么是可以接受的。
如前所述,Linux系统能够同时运行多个进程。
尽管我们同时说,但一次只能完成一个过程。
其他符合条件的进程必须等到资源变得可以自由处理为止。
这种情况发生得太快了,以至于我们觉得处理器一次要执行多项操作。
但是,是的,多核处理器(例如8核处理器)可以一次完成8个不同的任务(因为每个任务都由不同的核处理)。
显示的负载平均值指示等待运行的排队进程的数量(称为运行队列)。
在前面显示的输出中,我们可能已经看到我们的平均负载为7.0、6.50、5.40。
这意味着在最后一分钟内,运行队列中的平均值为7.0个进程,在最近5分钟中,运行队列中的平均值为6.50个进程,在最后15分钟中,运行队列中的平均值为5.40个进程。
现在的问题是如何检查Linux系统中的当前运行队列。
我们将在一段时间后看到。
这里要了解的重要一点是,每个进程在处理器对其进行处理之前都会先进入运行队列。
如前所述,每个内核都有自己的运行队列(这就是为什么将平均负载输出除以nproc命令的cpu内核输出总数的原因)。
流程进入运行队列后,便可以具有两种可能的状态。
它可以是可运行的也可以是被阻止的。
内核的工作是根据其优先级选择下一个要运行的进程。
请注意,显示的负载平均值是运行队列中的进程(无论其处于可运行状态还是处于阻塞状态)。
VMSTAT工具可用于检查运行队列中的进程总数。
让我们看一下vmstat工具的示例输出。
root@ubuntu1:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu--- r b swpd free buff cache si so bi bo in cs us sy id wa 1 0 0 315616 25852 56040 0 0 0 0 15 17 0 0 100 0 0 0 0 315616 25852 56040 0 0 0 0 19 21 0 0 100 0 0 0 0 315616 25852 56040 0 0 0 0 15 17 0 0 100 0 0 0 0 315616 25852 56040 0 0 0 0 18 21 0 0 100 0 0 0 0 315616 25852 56040 0 0 0 0 13 13 0 0 100 0
我在上面的vmstat命令中给定的参数1将要求它每1秒刷新一次。
输出显示多列。
前两列分别带有“ r”和“ b”,表示运行队列中具有可运行或者已阻止状态的进程数。
如前所述,Linux是一个多任务操作系统。
这意味着内核必须在进程之间多次切换。
尽管看起来很简单,但是处理器在执行多任务处理时必须执行多项操作。
为了同时运行多个进程(这是非常正常的),处理器必须执行以下操作。
- 在切换到另一个进程执行之前,处理器需要保存当前正在运行的进程的所有上下文信息。这是非常必要的,因为处理器稍后需要再次切换回该过程。
- 处理器必须获取要处理的新进程的上下文信息。
相关:Linux进程管理和监视教程
尽管上下文切换是一项不错的功能,并且对于多任务处理是必需的,但是上下文切换数量的增加可能会对性能产生严重影响。
因为处理器每次在进程之间切换时,都必须将当前状态存储到内存中,然后从内存中检索新进程的状态(这需要时间和处理能力)。
发生上下文切换可能有两个原因。
第一个是真正的处理器开关,由内核调度程序引导。
第二个原因是由于硬件和其他软件应用程序引起的中断。
我们将在一段时间后回到中断状态。
正如我们之前讨论的那样,当今大多数处理器都是多核的。
这意味着内部有多个处理器(在Linux内核中,核心是单独的处理器)。
通常,进程会随着时间的推移在不同处理器之间移动,具体取决于我们如何设置亲和力。
默认情况下,进程使用所有单独的处理器(核心)。
尽管多个处理器可以提高整体系统性能,但有时确实会影响多个进程的性能。
这是因为当一个进程从一个内核切换到另一个内核时,新处理器必须刷新其缓存。
现在想象一下,如果进程在8核心系统上运行,则在其生命周期内将有许多高速缓存刷新。
这意味着对性能的影响。
为了防止过多的缓存刷新,我们可以将进程设置为专门在一个内核上运行。
如果我们有8核处理器,则核数从0到7.
让我们看看服务器上几个进程的默认关联性。
可以使用称为任务集的命令来检查进程的亲和力。
[root@www ~]# taskset -c -p 6389 pid 6389's current affinity list: 0-7 [root@www ~]# taskset -c -p 6580 pid 6580's current affinity list: 0-7
上面显示的PID是mysql和nginx进程pid(-p 6389和-p 6580)。
由于我没有为这些进程中的任何一个设置亲和力,因此其默认亲和力为0-7.
这意味着它将在其生命周期内的所有8个内核上运行。
我们可以使用如下所示的相同命令来设置亲和力。
[root@www ~]# taskset -c 0,1 -p 6389
上面的命令会将进程ID 6389绑定到核心0和1(在8核心处理器中,计数从0到7开始)。
正如我们所讨论的,上下文切换很有用,因为它允许linux内核为每个进程分配时间费用。
一旦某个进程在允许的时间内完成执行,则处理器将从运行队列中取出另一个进程。
这是通过定期的计时器中断来管理的。
计时器中断的数量可能会有所不同,具体取决于内核版本和体系结构。
/proc是查找当前中断数量的地方。
由于我们在/proc中找到的值是由内核动态填充的,因此我们可能需要观看几次(每秒一次)。
要了解计时器中断的总数,我们需要查看以下文件,并在grep中查找“ timer”
root@ubuntu1:~# cat /proc/interrupts | grep timer 0: 49 IO-APIC-edge timer LOC: 139261 Local timer interrupts
这些是系统上当前真正的计时器中断。
在多核系统上,我们将能够看到该文件中每个处理器核的计时器中断。
编写一个小脚本,以每秒监视该文件中的计时器中断,以便可以获取每秒的计时器中断值。
现在,我们需要了解一些非常重要的知识。
从该文件中获得的值(/proc/interrupts)是内核触发的真正的计时器中断,用于切换进程...
如果系统发生的计时器中断数量非常多,大于每秒的计时器中断数量,那么某些应用程序会执行很多读/写或者说I/O请求。
现在,如何检查系统上上下文切换的总数。
可以通过以1秒为间隔运行vmstat命令来完成此操作,如下所示。
root@ubuntu1:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu--- r b swpd free buff cache si so bi bo in cs us sy id wa 1 0 0 235060 44896 104604 0 0 4 0 20 25 0 0 100 0 0 0 0 235052 44896 104604 0 0 0 0 18 41 0 0 100 0 0 0 0 235052 44896 104604 0 0 0 0 15 20 0 0 100 0 0 0 0 235052 44896 104604 0 0 0 0 32 24 0 1 99 0
vmstat输出中显示的cs列显示每秒的上下文切换总数。
另外in列还向我们显示每秒的中断(我说每秒是因为我们触发了vmstat以使用1个参数刷新每秒)。
之前我们确实看到过,多核处理器中的上下文切换有点贵,因为一个进程将不得不通过多个核进行切换。
我们还看到了如何在我们感兴趣的pid上设置亲和力,以便它不会在内核之间移动以节省cpu缓存刷新。
但是,我们如何检查进程当前正在运行的核心?
或者,我们将如何验证并交叉检查我们已更改了亲和力以在单个内核上运行的进程是否按预期工作?
这可以通过top命令来完成。
默认的top命令输出不显示这些详细信息。
要查看此详细信息,我们必须在顶部命令界面上按f键,然后按j(按j后按Enter键)。
现在,输出将为我们显示有关进程及其运行的处理器的详细信息。
示例输出如下所示。
top - 04:24:03 up 96 days, 13:41, 1 user, load average: 0.11, 0.14, 0.15 Tasks: 173 total, 1 running, 172 sleeping, 0 stopped, 0 zombie Cpu(s): 7.1%us, 0.2%sy, 0.0%ni, 88.4%id, 0.1%wa, 0.0%hi, 0.0%si, 4.2%st Mem: 1011048k total, 950984k used, 60064k free, 9320k buffers Swap: 524284k total, 113160k used, 411124k free, 96420k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ P COMMAND 12426 nginx 20 0 345m 47m 29m S 77.6 4.8 40:24.92 7 php-fpm 6685 mysql 20 0 3633m 34m 2932 S 4.3 3.5 63:12.91 4 mysqld 19014 root 20 0 15084 1188 856 R 1.3 0.1 0:01.20 4 top 9 root 20 0 0 0 0 S 1.0 0.0 129:42.53 1 rcu_sched 6349 memcache 20 0 355m 12m 224 S 0.3 1.2 9:34.82 6 memcached 1 root 20 0 19404 212 36 S 0.0 0.0 0:20.64 3 init 2 root 20 0 0 0 0 S 0.0 0.0 0:30.02 4 kthreadd 3 root 20 0 0 0 0 S 0.0 0.0 0:12.45 0 ksoftirqd/0
输出中的p列显示当前正在执行该进程的处理器核心号。
监视几分钟,将使我们了解pid在两者之间切换处理器核心。
我们还可以验证设置了亲和力的pid是否仅在该特定内核上运行(请记住,内核计数从0开始)
现在,尽管我们讨论了上下文切换,但没有讨论如何检查哪个进程正在执行大量上下文切换。
找出这一点对于查找导致系统性能问题的过程非常有帮助。
有一个非常好的工具可以做到这一点。
它称为pidstat。
该工具作为sysstat软件包的一部分提供。
Ubuntu用户可能必须安装sysstat才能获取此命令。
示例输出如下所示。
root@ubuntu1:~# pidstat -w Linux 3.8.0-29-generic (ubuntu1) 03/11/2014 _x86_64_ (1 CPU) 09:32:48 AM PID cswch/s nvcswch/s Command 09:32:48 AM 1 0.03 0.05 init 09:32:48 AM 2 0.01 0.00 kthreadd 09:32:48 AM 3 2.20 0.00 ksoftirqd/0 09:32:48 AM 5 0.00 0.00 kworker/0:0H 09:32:48 AM 6 0.00 0.00 kworker/u:0 09:32:48 AM 7 0.00 0.00 kworker/u:0H 09:32:48 AM 8 0.00 0.00 migration/0 09:32:48 AM 9 0.00 0.00 rcu_bh 09:32:48 AM 10 2.99 0.00 rcu_sched
我与pidstat一起使用的-w选项将向我们显示系统上所有进程的上下文切换详细信息。
pidstat手册页很好地解释了这些字段。
pidstat手册页中有关输出的说明如下所示。
cswch/s:每秒执行的任务的自愿上下文切换总数。
由于任务需要不可用的资源而导致任务阻塞时,会发生自愿上下文切换。
nvcswch/s:每秒执行的非自愿上下文切换总数。
当任务在其时间片的持续时间内执行,然后被迫放弃处理器时,会发生非自愿的上下文切换。
CPU性能监控涵盖了我们到目前为止讨论的所有概念。
为了简单起见,对其中一些进行了概述。
- 运行队列
- 上下文切换率
- 根据系统和特定用户的CPU利用率
- CPU花费的空闲时间
每个处理器具有2到3个进程的系统就可以(在每个处理器内核的运行队列中平均2到3个进程)。
如果vmstat命令显示的cpu利用率保持在下面显示的百分比值范围内,则对于8核处理器,平均24到25的负载平均是可以接受的。
- 用户时间的60%到70%
- 系统时间的30%到40%
- 空闲时间的5%到10%。
可以从vmstat输出中获取以上详细信息。
让我以1秒的间隔运行vmstat。
root@ubuntu1:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu--- r b swpd free buff cache si so bi bo in cs us sy id wa 0 0 0 166600 45256 169068 0 0 5 2 20 26 0 0 100 0 0 0 0 166592 45256 169068 0 0 0 0 23 47 0 0 100 0 0 0 0 166592 45256 169068 0 0 0 0 14 18 0 0 100 0 0 0 0 166592 45256 169068 0 0 0 0 38 30 1 0 99 0 0 0 0 166592 45256 169068 0 0 0 0 27 18 0 0 100 0 0 0 0 166592 45256 169068 0 0 0 0 23 40 0 0 100 0
由于我的系统什么也不做(运行队列中没有进程),因此我们可以看到处理器在用户部分(显示在us列)中花费了0%的时间,在系统部分(sy列显示)中花费了0%的时间。
如果我们根据前面提到的百分比级别对us,sy和id部分中的cpu利用率进行了平衡,则可以忽略大量的上下文切换。
vmstat是Linux中最好的工具,它可以得出关于系统上正在发生的事情的结论。
关于vmstat的另一个主要优点是,它只需很少的处理能力即可运行,因此即使在系统负载很重的情况下,也可以运行它来获取详细信息。
另一个称为mpstat的类似工具可用于获取有关所有不同内核及其各自统计信息的详细信息。
该命令的示例输出如下所示。
[root@www ~]# mpstat -P ALL Linux 3.11.6-x86_64 03/12/2014 _x86_64_ (8 CPU) 05:31:41 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 05:31:41 AM all 3.26 0.00 0.11 0.74 0.00 0.00 0.54 0.00 95.34 05:31:41 AM 0 1.12 0.00 0.16 1.41 0.00 0.00 0.39 0.00 96.93 05:31:41 AM 1 10.43 0.00 0.17 0.99 0.00 0.01 1.22 0.00 87.17 05:31:41 AM 2 7.47 0.00 0.19 0.76 0.00 0.01 0.89 0.00 90.69 05:31:41 AM 3 2.99 0.00 0.11 0.65 0.00 0.00 0.58 0.00 95.67 05:31:41 AM 4 1.34 0.00 0.07 0.58 0.00 0.00 0.40 0.00 97.61 05:31:41 AM 5 0.88 0.00 0.06 0.54 0.00 0.00 0.31 0.00 98.20 05:31:41 AM 6 0.91 0.00 0.05 0.52 0.00 0.00 0.28 0.00 98.23 05:31:41 AM 7 0.92 0.00 0.05 0.49 0.00 0.00 0.27 0.00 98.27
下面提到了几种方案,它们有助于了解系统上正在发生的事情。
- 如果vmstat中的us列在输出中过高,而没有类似级别的上下文切换,则可能单个进程使用处理器的时间要长得多
- 如果wa列同时也经历了一个过高的值(当us较高而cs显着较低时),则意味着导致us值保持较高的过程正在执行一些繁重的I/O操作。
- 如果发生的中断数量较多(在vmstat中的列中显示),而上下文切换的数量较少(由cs显示),则可能表明某个特定的应用程序(可能是单线程)正在发送过多的硬件请求。
请注意,以上几点仅是为了让我们对处于危机中的情况有个大致了解。
这些点不应被视为核心参考点。