共计 2875 个字符,预计需要花费 8 分钟才能阅读完成。
如何计算 CPU 占用率?
简略来说,过程的 CPU 占用率指的是 CPU 有多少工夫破费在了运行过程上。在 Linux 零碎里,过程运行的工夫是以 jiffies
[1] 统计的,通过计算jiffies * HZ
,就能够失去过程耗费的 CPU 工夫,再除以 CPU 的总工夫,就能够失去过程的 CPU 占用率:jiffies * HZ / total_time
。
ps 和 top 的不同之处
ps
和 top
是最罕用的两种查看 CPU 占用的形式,都能够用来疾速找到以后 CPU 占用率高的过程。但实际上这两个工具的统计形式是齐全不同的。
咱们用上面这个简略的 Go 程序来测试这两个工具的差异:
package main
import (
"bytes"
"fmt"
"strconv"
"sync"
"time"
)
var testData = []byte(`testdata`)
func testBuffer(idx int) {m := map[string]*bytes.Buffer{}
for i := 0; i < 100; i += 1 {buf, ok := m[strconv.Itoa(i)]
if !ok {buf = new(bytes.Buffer)
}
for j := 0; j < 1024; j += 1 {buf.Write(testData)
}
m[strconv.Itoa(i)] = buf
}
fmt.Println("done,", idx)
wg.Done()}
var wg sync.WaitGroup
func main() {
for i := 0; i < 10; i += 1 {wg.Add(1)
j := i
go testBuffer(j)
}
wg.Wait()
fmt.Println("sleeping")
time.Sleep(time.Hour)
}
而后咱们运行这个程序,通过 top
和ps aux
别离查看过程的 CPU 占用状况。
top -n 1
:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
39753 infini 20 0 14.663g 0.014t 1200 S 611.1 22.2 0:23.53 test-cpu
ps aux
:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
infini 39881 767 39.1 26505284 25791892 pts/16 Sl+ 07:04 0:38 ./test-cpu
能够看到,ps
和 top
统计的 CPU 占用率是近似的(因为工夫点并不齐全吻合,统计值也会有轻微差异)。两个工具的差别体现在 testBuffer
完结后,top
统计的 CPU 占用率曾经靠近于 0,然而 ps
仍然统计到很高的 CPU 占用率:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
infini 39881 82.3 42.4 28638148 27953532 pts/16 Sl+ 07:04 0:40 ./test-cpu
为什么 ps 和 top 的统计值会有差别?
这两个工具的差别来自于各自运行形式的不同:top 只能继续运行一段时间,而 ps 是立即返回的。这个差别体现在运行 top -n 1
和ps aux
时,top
是提早后返回的,而 ps
是立即返回的。这两种不同的运行形式就会反映在两个工具的统计算法上。
文章结尾咱们提到,Linux 的 CPU 工夫是依照 jiffies
统计的,思考到效率问题,Linux 只会统计总值,不会记录历史数据。对于 ps
来说,因为只能统计到瞬时值,这个瞬时值的统计算法就必然拿不到实时的 CPU 占用率,因为实时的占用率须要通过 (current_cpu_time - last_cpu_time) / time_duration
来失去,ps
只能统计一次,所以 time_duration
为0
,也就无奈计算这个占用率。实际上,ps
统计的是整个过程运行周期内的 CPU 占用率[2]:
(total_cpu_time / total_process_uptime)
对于测试程序这种短时间的占用率回升,刚开始的时候 ps
可能统计到近似精确的均匀 CPU 占用率,然而 cpu 占用复原后,ps
的统计值并不会立即降落,而是会随着过程运行工夫 total_process_uptime
的减少迟缓降落。
top
命令不同,top
是通过继续运行来更新 CPU 占用率统计的。-n 1
这个参数指定 top
运行一个迭代后退出,top
命令就能够通过这个提早来能够实现一个迭代内的 CPU 占用率统计:
(current_cpu_time - last_cpu_time) / iteration_duration
如何继续监控 CPU 占用率?
通常来说,监控零碎分为采集和统计两个不同的组件,采集组件只会采集指标数值,统计性能通过数据库 /Dashboard 来实现。要监控 CPU 占用率,ps
是一个十分合乎采集组件行为的统计形式,每次采集都能够拿到“以后”的 CPU 占用率。然而受限于算法自身的统计形式,咱们理论采集到的是均匀 CPU 占用率,无奈反映过程的实时状态。
以 INFINI Console 为例,咱们运行一个短时间的数据迁徙工作负载,而后查看对应 INFINI 网关实例的 CPU 占用监控(payload.instance.system.cpu
,通过 ps
形式统计以后 CPU 占用率)。能够看到,CPU 占用率会以一个曲线回升,在工作完结后会迟缓降落:
如果想继续监控实时 CPU 占用率,咱们就须要借鉴 top
的统计形式,采集原始的过程 CPU 工夫,进而通过聚合数据来计算 CPU 占用率。
在 Linux 零碎下,ps
和 top
命令都会通过 /proc/[PID]/stat
提供的信息来计算 CPU 占用率[2]:
## Name Description
14 utime CPU time spent in user code, measured in jiffies
15 stime CPU time spent in kernel code, measured in jiffies
16 cutime CPU time spent in user code, including time from children
17 cstime CPU time spent in kernel code, including time from children
获取到每个采样工夫的过程信息后,咱们就能够通过这个公式来计算采样周期内的 CPU 占用率:
delta(cpu_time) / delta(timestamp)
在 INFINI Console,咱们能够通过 deriative
函数来计算 payload.instance.system.user_in_ms
和payload.instance.system.sys_in_ms
绝对于 timestamp
的占比,进而失去精确的 CPU 占用率统计。
这样,咱们就能够统计到网关在运行工作负载前后的实时 CPU 占用率:
总结
尽管 top
和ps
都能够统计 CPU 占用率,但统计算法却齐全不同。理解这两种算法的底层原理之后,咱们就能够设计出适宜监控零碎的数据采集和数据统计形式,采集到精确的 CPU 占用率。
参考
- Jiffies
-
Top and ps not showing the same cpu result
本文由博客一文多发平台 OpenWrite 公布!