当系统性能变低时(俗称卡顿),我们可以从平均负载入手,找到引发根源,然后解决。
什么是平均负载?
单位时间内,系统中处于可运行状态和不可中断状态的平均进程数。
对上述状态释义如下:
- 可运行状态进程:正在使用 CPU 、或是正在等待 CPU 的进程。用命令
ps
看到 STAT 为 R (Running,Runable)。 不可中断状态进程:不可以被中断的进程,如等待硬件设备的I/O响应。用命令
ps
看到 STAT 为 D(Uninterruptible Sleep,也叫 Disk Sleep)。如何查看平均负载?
可用命令 uptime
:
Guan@Orchard:~$ uptime
22:11:31 up 222 days, 23:10, 1 user, load average: 0.00, 0.04, 0.01
可以看到 load average 后面有三个数值,分别表示前 1 分钟,前 5 分钟和前 15 分钟的平均负载。
如果假设当前平均负载为 2 ,则意味着:
- 在只有 2 个 CPU 的系统上,所有 CPU 刚好沾满;
- 在只有 1 个 CPU 的系统上,有一半的进程竞争不到 CPU;
- 在有 4 个 CPU 的系统上,CPU 有 50% 的空闲。
这里建议:当平均负载高于 CPU 数量的 70% 时,应该开始分析排查负载高的问题。
查看系统 CPU 数量的方法:grep "model name" /proc/cpuinfo | wc -l
。
平均负载!=CPU使用率
当我们发现电脑卡顿,一般会马上去看 CPU 使用率,通常 top
命令,或者 htop
。事实上,我们还可以看平均负载,因为过高的负载也会造成机器性能下降。需要说明的是:$平均负载 != CPU 使用率$。
CPU 使用率是指:单位时间内 CPU 繁忙情况的统计。而平均负载不但包括正在使用 CPU 的进程,还包括等待 CPU 的进程,以及等待 I/O 的进程。
二者关系可分三种情况讨论:
- CPU密集型进程:使用大量 CPU 会导致平均负载升高,此时二者一致;
- I/O密集型进程:等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
- 大量进程:大量等待 CPU 的进程调度会导致平均负载升高,此时 CPU 使用率也会比较高。
Python 实验
以下用 Python 程序模拟 CPU 密集,I/O 密集,大量进程等待调度三种情况。都基于腾讯的学生优惠套餐服务器,也就是 1 核 2G 那种。
第一种情况:CPU 密集
# CPU 密集型
def test_func():
# 死循环,自增 1
x = 0
while True:
x += 1
test_func()
跑上段代码前,可以先使用 top
,方便观察 CPU 使用率; watch -d uptime
方便观察平均负载的变化。
在我的服务器上,CPU 很快飙到 99%+ ,一段时间后平均负载也上升到了 1.00+ 。
# top 命令
%Cpu(s): 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
# uptime 命令
23:16:25 up 223 days, 15 min, 4 users, load average: 1.05, 0.91, 0.61
即:使用大量 CPU 会导致平均负载升高,正确。
第二种情况:I/O 密集
# I/O密集型
import os
import time
import random
from threading import Thread
def test_func():
while True:
filename = ".{}-{}".format(int(time.time()), random.randrange(10000))
with open(filename, "w+") as f:
f.write("*" * 1000)
f.flush()
print(f.read())
for __ in range(50):
t = Thread(target=test_func)
t.start()
else:
t.join()
为使效果明显,我开了很多线程,并且都在以“死循环”的方式的做I/O操作。此时在我的服务器上,CPU 使用率只是略有升高,而平均负载飙到了 39+ 。
# I/O 密集
%Cpu(s): 3.6 us, 13.1 sy, 0.0 ni, 0.0 id, 83.2 wa, 0.0 hi, 0.0 si, 0.0 st
# uptime 命令
23:45:41 up 223 days, 44 min, 4 users, load average: 39.26, 14.98, 6.30
即:等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高,正确。
第三种情况:大量进程
# 大量进程
import time
from multiprocessing import Process
def test_func():
while True:
x = 0
x += 1
for __ in range(50):
p = Process(target=test_func)
p.start()
else:
p.join()
此次也开启了 50 个进程,通过 top
可以看到,尽管每个 python 带起来的进程只占用很少的 CPU ,这里清一色是 2.2% 。最后结果是 CPU 上升至 100% ,前1 分钟的平均负载达到了 49+ 。
# uptime 命令
00:04:24 up 223 days, 1:03, 4 users, load average: 49.71, 28.25, 13.58
即:大量等待 CPU 的进程调度会导致平均负载、CPU 使用率升高,正确。
感谢
- 参考极客时间《Linux性能优化实战》到底应该怎么理解“平均负载”?
倪朋飞老师建议用 pidstat
和 mpstat
作为性能分析工具,但因我的环境问题,暂时没装上,但 top
和 uptime
也够看个大概了。
还不快抢沙发