一、平均负载

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

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

不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps aux 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。

所以, top 命令中的

load average: 0.10, 0.04, 0.05 表示:

一分钟内 平均活跃进程数为 0.10个

五分钟内 平均活跃进程数为 0.04个

十五分钟内 平均活跃进程数为 0.05个

计算规则 : 在Linux系统中,是每间隔$5HZ$或者$5秒$统计一次运行的任务数,然后计算均值。

 

平均负载与cpu个数的关系 :

获取cpu个数命令 :

grep 'model name' /proc/cpuinfo | wc -l

理想情况下, 应该是每个cpu上运行一个程序, 平均负载的值等于cpu个数。

通过三个时间可以判定cpu负载的趋势。

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

查看负载命令:

uptime

openwrt 手动 负载均衡 openwrt调节cpu_数据

查看各cpu使用率变化的命令 :

# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5 秒后输出一组数据

$ mpstat -P ALL 5

openwrt 手动 负载均衡 openwrt调节cpu_openwrt 手动 负载均衡_02

查看当前有哪些进程在使用 cpu 命令 :

# 间隔 5 秒后输出一组数据

$ pidstat -u 5 1

openwrt 手动 负载均衡 openwrt调节cpu_用户态_03

 

二、cpu使用率

Linux 通过 /proc 虚拟文件系统,向用户空间提供了系统内部状态的信息,而 /proc/stat 提供的就是系统的 CPU 和任务统计信息。

# 只保留各个 CPU 的数据

$ cat /proc/stat | grep ^cpu

cpu  280580 7407 286084 172900810 83602 0 583 0 0 0

cpu0 144745 4181 176701 86423902 52076 0 301 0 0 0

cpu1 135834 3226 109383 86476907 31525 0 282 0 0 0

这里的输出结果是一个表格。其中,第一列表示的是 CPU 编号,如 cpu0、cpu1 ,而第一行没有编号的 cpu ,表示的是所有 CPU 的累加。其他列则表示不同场景下 CPU 的累加节拍数,它的单位是 USER_HZ,也就是 10 ms(1/100 秒),所以这其实就是不同场景下的 CPU 时间。

user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。

nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。

system(通常缩写为 sys),代表内核态 CPU 时间。

idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。

iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。

irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。

softirq(通常缩写为 si),代表处理软中断的 CPU 时间。

steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。

guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。

guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。

通常所说的 CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比,用公式来表示就是

openwrt 手动 负载均衡 openwrt调节cpu_优先级_04

也可以用每一个场景的 CPU 时间,除以总的 CPU 时间,计算出每个场景的 CPU 使用率。

比如 :

 

user

nice

system

idle

iowait

irq

softirq

steal

guest

guest_nice

cpu

280580

7407

286084

172900810

83602

0

583

0

0

0

cpu0

144745

4181

176701

86423902

52076

0

301

0

0

0

cpu1

135834

3226

109383

86476907

31525

0

282

0

0

0

Cpu总使用率 = 1-172900810/(280580+7407+286084+172900810+83602+0+583+0+0+0) = 0.003792691532460757 = 0.3792691532460757%

不过这里记录的是一直累计的结果, 而我们获取cpu使用率一般是当前使用率, 所以我们会取一个时间差,得到这段时间的平均cpu使用率。

openwrt 手动 负载均衡 openwrt调节cpu_openwrt 手动 负载均衡_05

性能分析工具给出的都是间隔一段时间的平均 CPU 使用率,所以要注意间隔时间的设置,特别是用多个工具对比分析时,你一定要保证它们用的是相同的间隔时间。

比如 :

openwrt 手动 负载均衡 openwrt调节cpu_openwrt 手动 负载均衡_06

总Cpu平均使用时间 =

1 - float64(1235020245-1235017470)/float64((1189661+78356+2269914+1235020245+2533097+0+103995+0+0+0)-(1189657+78356+2269913+1235017470+2533097+0+103995+0+0+0))

= 0.0017985611510791255 = 0.17985611510791255%

而 top(默认每 3 秒刷新一次,按下数字 1 ,就可以切换到每个 CPU 的使用率) 看到的结果也差不多

openwrt 手动 负载均衡 openwrt调节cpu_优先级_07

显示进程较详细cpu使用率 :

# 每隔 1 秒输出一组数据,共输出 5 组
$ pidstat 1 5

通过以上操作, 基本上可以定位到是哪些程序cpu使用率过高。

但是找到程序之后, 如果想要优化, 就要确定是哪一个函数、那段代码导致的cpu使用率过高, 怎么做到呢?

使用 perf 工具

类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数。

三、实例

go 程序如下 :

func test4(a int64) {
	fmt.Println(a)
	for {
		a++
	}
}

func test3(a int64) {
	for a < 1000000000 {
		a++
	}
	test4(a)
}

func test2(a int64) {
	for a < 1000000 {
		a++
	}
	test3(a)
}

func test(a int64) {
	for a < 100000 {
		a++
	}
	test2(a)
}

func main() {
	test(1)
}

运行后,

1、使用top命令查看cpu使用情况

openwrt 手动 负载均衡 openwrt调节cpu_openwrt 手动 负载均衡_08

2、使用 pidstat 1 5 命令找到使用 cpu 的进程的进程号

openwrt 手动 负载均衡 openwrt调节cpu_用户态_09

3、使用 perf top -g -p 进程号 命令查看调用情况

openwrt 手动 负载均衡 openwrt调节cpu_优先级_10

4、可以使用上下键选中 main.test4 这行, 然后按回车展开函数调用栈:

openwrt 手动 负载均衡 openwrt调节cpu_openwrt 手动 负载均衡_11

将采样保存到文件中回放 :

$ perf record # 按 Ctrl+C 终止采样  指定进程 : perf record -g -p 71617
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]

$ perf report # 展示类似于 perf top 的报告 指定进程 : perf report -g -p 71617