Linux性能优化(一)

如何理解平均负载

Linux性能优化(一)

如何理解平均负载

uptime

# uptime                                                                                                                         root@iZbp14ipzpabr30yllskn4Z
 14:37:58 up 403 days,  1:48,  4 users,  load average: 0.74, 0.63, 0.60
 ~
#  而最后三个数字呢,依次则是过去 1 分钟、5 分钟、15 分钟的平均负载(Load Average)。

平均负载


   平均负载是指单位时间内,系统处**于可运行状态和不可中断状态**的平均进程数,也就是**平均活跃进程数**,它和 CPU 使用率并没有直接关系。这里我先解释下,可运行状态和不可中断状态这俩词儿。

所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。

不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

既然平均的是活跃进程数,那么最理想的,就是每个 CPU 上都刚好运行着一个进程,这样每个 CPU 都得到了充分利用。比如当平均负载为 2 时,意味着什么呢?

	* 在只有 2 个 CPU 的系统上,意味着所有的 CPU 都刚好被完全占用。
	* 在 4 个 CPU 的系统上,意味着 CPU 有 50% 的空闲。
	* 而在只有 1 个 CPU 的系统中,则意味着有一半的进程竞争不到 CPU。

查看CPU个数

[root@VM-64-25-centos ~]# grep 'model name' /proc/cpuinfo  | wc -l
8
[root@VM-64-25-centos ~]#

平均负载为多少时合理

* 如果 1 分钟、5 分钟、15 分钟的三个值基本相同,或者相差不大,那就说明系统负载很平稳。
* 但如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少,而过去 15 分钟内却有很大的负载。
* 反过来,如果 1 分钟的值远大于 15 分钟的值,就说明最近 1 分钟的负载在增加,这种增加有可能只是临时性的,也有可能还会持续增加下去,所以就需要持续观察。一旦 1 分钟的平均负载接近或超过了 CPU 的个数,就意味着系统正在发生过载的问题,这时就得分析调查是哪里导致的问题,并要想办法优化了。

那么,在实际生产环境中,平均负载多高时,需要我们重点关注呢?

**在我看来,当平均负载高于 CPU 数量 70% 的时候,**你就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能。

**但 70% 这个数字并不是绝对的**,最推荐的方法,还是把系统的平均负载监控起来,然后根据更多的历史数据,判断负载的变化趋势。当发现负载有明显升高趋势时,比如说负载翻倍了,你再去做分析和调查。

平均负载与 CPU 使用率

现实工作中,我们经常容易把平均负载和 CPU 使用率混淆,所以在这里,我也做一个区分。

可能你会疑惑,既然平均负载代表的是活跃进程数,那平均负载高了,不就意味着 CPU 使用率高吗?

我们还是要回到平均负载的含义上来,平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。

而 CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:

* CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
* I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
* 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。

平均负载案例分析

我们以三个示例分别来看这三种情况,并用 iostat、mpstat、pidstat 等工具,找出平均负载升高的根源。

测试准备工作

机器配置:2 CPU,8GB 内存。预先安装 stress 和 sysstat 包,如 apt install stress sysstat。

在这里,我先简单介绍一下 stress 和 sysstat。
* stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。

* 而 sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpstat 和 pidstat。
* **mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。**
* **pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。**

**此外,每个场景都需要你开三个终端,登录到同一台 Linux 机器中。**

先安装stress sysstat

[root@VM-64-25-centos ~]# yum -y install stress sysstat

rpm update sysstat

[root@VM-64-25-centos ~]# wget https://rpmfind.net/linux/centos/8.1.1911/AppStream/x86_64/os/Packages/sysstat-11.7.3-2.el8.x86_64.rpm
--2020-10-12 16:12:25--  https://rpmfind.net/linux/centos/8.1.1911/AppStream/x86_64/os/Packages/sysstat-11.7.3-2.el8.x86_64.rpm
Resolving rpmfind.net (rpmfind.net)... 195.220.108.108
Connecting to rpmfind.net (rpmfind.net)|195.220.108.108|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 435888 (426K) [application/x-rpm]
Saving to: ‘sysstat-11.7.3-2.el8.x86_64.rpm’

100%[==========================================================================================================>] 435,888     15.0KB/s   in 26s

2020-10-12 16:12:53 (16.4 KB/s) - ‘sysstat-11.7.3-2.el8.x86_64.rpm’ saved [435888/435888]

[root@VM-64-25-centos ~]# ls
sysstat-11.7.3-2.el8.x86_64.rpm
[root@VM-64-25-centos ~]# rpm -Uvh sysstat-11.7.3-2.el8.x86_64.rpm
warning: sysstat-11.7.3-2.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:sysstat-11.7.3-2.el8             ################################# [ 50%]
Cleaning up / removing...
   2:sysstat-10.1.5-19.el7            ################################# [100%]
[root@VM-64-25-centos ~]#

测试1: CPU密集型进程

首先,我们在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:

[root@VM-64-25-centos ~]# stress --cpu 1 --timeout 600
stress: info: [5393] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd

在第二个终端能看到

top - 15:18:24 up 110 days,  6:27,  3 users,  load average: 0.98, 0.58, 0.27
Tasks: 139 total,   2 running, 137 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.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu4  :100.0 us,  0.0 sy,  0.0 ni,  0.0 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
KiB Mem : 32779660 total, 29352228 free,   439752 used,  2987680 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 31936472 avail Mem

在第三个终端使用mpstat查看

[root@VM-64-25-centos ~]# mpstat -P ALL 5
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos)     10/12/2020      _x86_64_        (8 CPU)

03:16:54 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
03:16:59 PM  all   12.56    0.00    0.05    0.00    0.00    0.00    0.00    0.00    0.00   87.39
03:16:59 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
03:16:59 PM    1    0.00    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00   99.80
03:16:59 PM    2    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00   99.80
03:16:59 PM    3    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00   99.80
03:16:59 PM    4  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
03:16:59 PM    5    0.00    0.00    0.20    0.00    0.00    0.00    0.00    0.00    0.00   99.80
03:16:59 PM    6    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
03:16:59 PM    7    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

使用pidstat来查看那个进程导致CPU使用率100%

[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos)     10/12/2020      _x86_64_        (8 CPU)

03:19:33 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
03:19:38 PM     0      5394  100.00    0.00    0.00  100.00     4  stress
03:19:38 PM     0     27987    0.20    0.00    0.00    0.20     2  barad_agent
03:19:38 PM     0     27988    0.60    0.40    0.00    1.00     2  barad_agent
03:19:38 PM     0     28457    0.20    0.20    0.00    0.40     2  YDService

Average:      UID       PID    %usr %system  %guest    %CPU   CPU  Command
Average:        0      5394  100.00    0.00    0.00  100.00     -  stress
Average:        0     27987    0.20    0.00    0.00    0.20     -  barad_agent
Average:        0     27988    0.60    0.40    0.00    1.00     -  barad_agent
Average:        0     28457    0.20    0.20    0.00    0.40     -  YDService
[root@VM-64-25-centos ~]#

测试2: I/O密集型进程

首先还是运行 stress 命令,但这次模拟 I/O 压力,即7个线程不停地执行,sync:
[root@VM-64-25-centos ~]# stress -i 7 --timeout 600
stress: info: [9331] dispatching hogs: 0 cpu, 7 io, 0 vm, 0 hdd
在第二个终端查看uptime的变化,我的测试机器是8C的,可以多观察一会
Every 2.0s: uptime                                                                                                          Mon Oct 12 15:37:01 2020

 15:37:01 up 110 days,  6:46,  3 users,  load average: 6.67, 3.71, 1.69

在第三个终端查看CPU的变化

# 间隔5秒输出一组数据
[root@VM-64-25-centos ~]# mpstat -P ALL 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos)     10/12/2020      _x86_64_        (8 CPU)

03:37:28 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
03:37:33 PM  all    0.10    0.00   26.70    0.90    0.00    0.07    0.00    0.00    0.00   72.22
03:37:33 PM    0    0.00    0.00   80.24    2.59    0.00    0.20    0.00    0.00    0.00   16.97
03:37:33 PM    1    0.20    0.00   41.43    1.20    0.00    0.00    0.00    0.00    0.00   57.17
03:37:33 PM    2    0.20    0.00    0.20    0.00    0.00    0.60    0.00    0.00    0.00   99.00
03:37:33 PM    3    0.20    0.00    0.40    0.00    0.00    0.00    0.00    0.00    0.00   99.40
03:37:33 PM    4    0.00    0.00   19.20    1.00    0.00    0.00    0.00    0.00    0.00   79.80
03:37:33 PM    5    0.00    0.00   30.86    1.20    0.00    0.00    0.00    0.00    0.00   67.94
03:37:33 PM    6    0.20    0.00   26.40    1.00    0.00    0.00    0.00    0.00    0.00   72.40
03:37:33 PM    7    0.00    0.00   14.60    0.60    0.00    0.00    0.00    0.00    0.00   84.80

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
Average:     all    0.10    0.00   26.70    0.90    0.00    0.07    0.00    0.00    0.00   72.22
Average:       0    0.00    0.00   80.24    2.59    0.00    0.20    0.00    0.00    0.00   16.97
Average:       1    0.20    0.00   41.43    1.20    0.00    0.00    0.00    0.00    0.00   57.17
Average:       2    0.20    0.00    0.20    0.00    0.00    0.60    0.00    0.00    0.00   99.00
Average:       3    0.20    0.00    0.40    0.00    0.00    0.00    0.00    0.00    0.00   99.40
Average:       4    0.00    0.00   19.20    1.00    0.00    0.00    0.00    0.00    0.00   79.80
Average:       5    0.00    0.00   30.86    1.20    0.00    0.00    0.00    0.00    0.00   67.94
Average:       6    0.20    0.00   26.40    1.00    0.00    0.00    0.00    0.00    0.00   72.40
Average:       7    0.00    0.00   14.60    0.60    0.00    0.00    0.00    0.00    0.00   84.80
[root@VM-64-25-centos ~]#

从这里可以看到,1分钟的负载增加到6.67,其中一个CPU的系统CPU使用率达到80.24,而iowait达到2.59,说明平均负载的升高是由iowait导致的

那么是那个进程导致iowait这么高,我们用pidstat来查询,如图展示发现是stress进程导致的

[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos)     10/12/2020      _x86_64_        (8 CPU)

03:39:55 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
03:40:00 PM     0        18    0.00    0.20    0.00    0.20     2  migration/2
03:40:00 PM     0       846    0.00    0.20    0.00    0.20     5  kworker/5:1H
03:40:00 PM     0       969    0.00    0.20    0.00    0.20     7  kworker/7:1H
03:40:00 PM     0      8401    0.00    0.20    0.00    0.20     3  kworker/u16:2
03:40:00 PM     0      9332    0.00   23.40    0.00   23.40     0  stress
03:40:00 PM     0      9333    0.00   52.40    0.00   52.40     5  stress
03:40:00 PM     0      9334    0.00   31.40    0.00   31.40     4  stress
03:40:00 PM     0      9335    0.00   26.60    0.00   26.60     6  stress
03:40:00 PM     0      9336    0.00   19.00    0.00   19.00     0  stress
03:40:00 PM     0      9337    0.00   36.20    0.00   36.20     7  stress
03:40:00 PM     0      9338    0.00   14.60    0.00   14.60     1  stress
03:40:00 PM     0     10203    0.00    0.40    0.00    0.40     2  kworker/u16:0
03:40:00 PM     0     27987    0.20    0.00    0.00    0.20     2  barad_agent
03:40:00 PM     0     27988    0.20    0.20    0.00    0.40     1  barad_agent
03:40:00 PM     0     28539    0.00    0.20    0.00    0.20     5  YDEdr

Average:      UID       PID    %usr %system  %guest    %CPU   CPU  Command
Average:        0        18    0.00    0.20    0.00    0.20     -  migration/2
Average:        0       846    0.00    0.20    0.00    0.20     -  kworker/5:1H
Average:        0       969    0.00    0.20    0.00    0.20     -  kworker/7:1H
Average:        0      8401    0.00    0.20    0.00    0.20     -  kworker/u16:2
Average:        0      9332    0.00   23.40    0.00   23.40     -  stress
Average:        0      9333    0.00   52.40    0.00   52.40     -  stress
Average:        0      9334    0.00   31.40    0.00   31.40     -  stress
Average:        0      9335    0.00   26.60    0.00   26.60     -  stress
Average:        0      9336    0.00   19.00    0.00   19.00     -  stress
Average:        0      9337    0.00   36.20    0.00   36.20     -  stress
Average:        0      9338    0.00   14.60    0.00   14.60     -  stress
Average:        0     10203    0.00    0.40    0.00    0.40     -  kworker/u16:0
Average:        0     27987    0.20    0.00    0.00    0.20     -  barad_agent
Average:        0     27988    0.20    0.20    0.00    0.40     -  barad_agent
Average:        0     28539    0.00    0.20    0.00    0.20     -  YDEdr
[root@VM-64-25-centos ~]#

测试3: 大量进程的场景

当系统中运行的进程超出CPU运行能力时,就会出现等待CPU的进程.

比如,我们还是使用stress来测试,我们的CPU是8C,我们模拟20C.

[root@VM-64-25-centos ~]# stress -c 20 --timeout 600
stress: info: [13688] dispatching hogs: 20 cpu, 0 io, 0 vm, 0 hdd

使用uptime来看负载的变化,明显出现过载情况

Every 2.0s: uptime                                                                                                          Mon Oct 12 16:17:19 2020

 16:17:19 up 110 days,  7:26,  3 users,  load average: 5.14, 1.30, 1.77

使用pidstat来查看进程

[root@VM-64-25-centos ~]# pidstat -u 5 1
Linux 3.10.0-1062.18.1.el7.x86_64 (VM-64-25-centos)     10/12/2020      _x86_64_        (8 CPU)

04:19:51 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
04:19:56 PM     0     13099    0.20    0.00    0.00    0.60    0.20     1  watch
04:19:56 PM     0     19633   42.20    0.00    0.00   57.80   42.20     1  stress
04:19:56 PM     0     19634   40.60    0.00    0.00   59.80   40.60     3  stress
04:19:56 PM     0     19635   40.40    0.00    0.00   59.40   40.40     0  stress
04:19:56 PM     0     19636   39.00    0.00    0.00   61.40   39.00     2  stress
04:19:56 PM     0     19637   36.20    0.00    0.00   63.80   36.20     6  stress
04:19:56 PM     0     19638   41.80    0.00    0.00   58.40   41.80     5  stress
04:19:56 PM     0     19639   42.00    0.00    0.00   57.40   42.00     2  stress
04:19:56 PM     0     19640   40.20    0.00    0.00   60.20   40.20     4  stress
04:19:56 PM     0     19641   40.60    0.00    0.00   59.40   40.60     4  stress
04:19:56 PM     0     19642   38.80    0.00    0.00   61.40   38.80     4  stress
04:19:56 PM     0     19643   41.40    0.00    0.00   58.80   41.40     5  stress
04:19:56 PM     0     19644   43.20    0.00    0.00   57.20   43.20     3  stress
04:19:56 PM     0     19645   36.60    0.00    0.00   64.00   36.60     0  stress
04:19:56 PM     0     19646   38.40    0.00    0.00   61.60   38.40     7  stress
04:19:56 PM     0     19647   38.60    0.00    0.00   61.20   38.60     5  stress
04:19:56 PM     0     19648   40.20    0.00    0.00   59.80   40.20     0  stress
04:19:56 PM     0     19649   43.00    0.00    0.00   57.20   43.00     6  stress
04:19:56 PM     0     19650   38.60    0.00    0.00   61.60   38.60     1  stress
04:19:56 PM     0     19651   37.40    0.00    0.00   62.60   37.40     2  stress
04:19:56 PM     0     19652   40.60    0.00    0.00   59.80   40.60     7  stress
04:19:56 PM     0     20344    0.00    0.20    0.00    0.00    0.20     1  pidstat
04:19:56 PM     0     27988    0.00    0.20    0.00    0.00    0.20     2  barad_agent

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0     13099    0.20    0.00    0.00    0.60    0.20     -  watch
Average:        0     19633   42.20    0.00    0.00   57.80   42.20     -  stress
Average:        0     19634   40.60    0.00    0.00   59.80   40.60     -  stress
Average:        0     19635   40.40    0.00    0.00   59.40   40.40     -  stress
Average:        0     19636   39.00    0.00    0.00   61.40   39.00     -  stress
Average:        0     19637   36.20    0.00    0.00   63.80   36.20     -  stress
Average:        0     19638   41.80    0.00    0.00   58.40   41.80     -  stress
Average:        0     19639   42.00    0.00    0.00   57.40   42.00     -  stress
Average:        0     19640   40.20    0.00    0.00   60.20   40.20     -  stress
Average:        0     19641   40.60    0.00    0.00   59.40   40.60     -  stress
Average:        0     19642   38.80    0.00    0.00   61.40   38.80     -  stress
Average:        0     19643   41.40    0.00    0.00   58.80   41.40     -  stress
Average:        0     19644   43.20    0.00    0.00   57.20   43.20     -  stress
Average:        0     19645   36.60    0.00    0.00   64.00   36.60     -  stress
Average:        0     19646   38.40    0.00    0.00   61.60   38.40     -  stress
Average:        0     19647   38.60    0.00    0.00   61.20   38.60     -  stress
Average:        0     19648   40.20    0.00    0.00   59.80   40.20     -  stress
Average:        0     19649   43.00    0.00    0.00   57.20   43.00     -  stress
Average:        0     19650   38.60    0.00    0.00   61.60   38.60     -  stress
Average:        0     19651   37.40    0.00    0.00   62.60   37.40     -  stress
Average:        0     19652   40.60    0.00    0.00   59.80   40.60     -  stress
Average:        0     20344    0.00    0.20    0.00    0.00    0.20     -  pidstat
Average:        0     27988    0.00    0.20    0.00    0.00    0.20     -  barad_agent
[root@VM-64-25-centos ~]#

可以看出,20个进程在争抢 8 个 CPU,每个进程等待 CPU 的时间(也就是代码块中的 %wait 列)高达 60%。这些超出 CPU 计算能力的进程,最终导致 CPU 过载。

理解平均负载

平均负载提供了一个快速查看系统整体性能的手段,反映了整体的负载情况。但只看平均负载本身,我们并不能直接发现,到底是哪里出现了瓶颈。所以,在理解平均负载时,也要注意:
* 平均负载高有可能是 CPU 密集型进程导致的;
* 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
* 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源。

pidstat输出中没有%wait的问题,是因为CentOS默认的sysstat稍微有点老,源码或者RPM升级到11.5.5版本以后就可以看到了。而Ubuntu的包一般都比较新,没有这个问题。