本文总结了一些常见的 Linux 系统监控指标,和它们的计算方式,作为备忘笔记。

CPU 使用率

CPU 使用率衡量的是程序运行占用的 CPU 百分比。Linux 的 CPU 使用率信息可以通过/proc/stat 文件计算得到。/proc/stat包含了所有 CPU 活动的信息,该文件中的所有值都是从系统启动开始累计的,单位为 jiffies。如下图所示,cpu 一行指的是总的 CPU 信息,cpu0、cpu1、cpu2、cpu3 几行指的是 CPU 各个核的 CPU 信息。从这里也可以看出这台服务器共有 4 个核。每列从左到右的意思

  • **user:**从系统启动开始累计到当前时刻,用户态的 CPU 时间 ,不包含 nice 值为负进程所占用的时间
  • **nice:**从系统启动开始累计到当前时刻,nice 值为负的进程所占用的 CPU 时间
  • **system:**从系统启动开始累计到当前时刻,内核态时间
  • **idle:**从系统启动开始累计到当前时刻,除硬盘 IO 等待时间以外其它等待时间
  • **iowait:**从系统启动开始累计到当前时刻,硬盘 IO 等待时间
  • **irq:**从系统启动开始累计到当前时刻,硬中断时间
  • **softirq:**从系统启动开始累计到当前时刻,软中断时间
  • **steal:**在虚拟环境下 CPU 花在处理其他操作系统的时间,Linux 2.6.11 开始才开始支持。
  • **guest:**在 Linux 内核控制下 CPU 为 guest 操作系统运行虚拟 CPU 的时间,Linux 2.6.24 开始才开始支持。
  • guest_nice: 在 Linux 内核控制下 CPU 为 guest 操作系统在虚拟 CPU 中运行 nice 进程的时间,Linux 2.6.33 开始才开始支持。
1
2
3
4
5
6
$ cat /proc/stat | grep cpu
cpu  180296 204 123070 30283108 13956 0 2046 0 0 0
cpu0 45360 53 30785 7560073 10631 0 771 0 0 0
cpu1 45266 47 30779 7573915 1373 0 508 0 0 0
cpu2 44442 54 30724 7574282 1257 0 405 0 0 0
cpu3 45228 48 30781 7574835 693 0 360 0 0 0

根据这些信息,就可以计算出 CPU 使用率。网管 Agent 的 CPU 使用率采集算法如下(以 CPU0 为例):

  • cat /proc/stat | grep ‘cpu0’得到 cpu0 的信息
  • cpu_total1=user+nice+system+idle+iowait+irq+softirq
  • cpu_used1=user+nice+system+irq+softirq
  • sleep 15 秒
  • 再次 cat /proc/stat | grep ‘cpu0’得到 cpu 的信息
  • cpu_total2=user+nice+system+idle+iowait+irq+softirq
  • cpu_used2=user+nice+system+irq+softirq
  • 得到 cpu0 在 15 秒内的平均使用率:(cpu_used2 - cpu_used1) / (cpu_total2 - cpu_total1) * 100%

每分钟会采集 4 次 15 秒内的 CPU 平均使用率。为了避免漏采集 CPU 峰值,可以取这一分钟内四次采集的最大值上报。

CPU 负载

系统负载指的是计算机系统执行计算工作的表现,CPU 负载指的是在一段时间内计算机的系统负载,一般用 1 分钟内、5 分钟内、15 分钟内这三个数字衡量。通过 uptime命令可以显示 CPU 负载。

1
2
$ uptime
 14:34:03 up 10:43,  4 users,  load average: 0.06, 0.11, 0.09
  • 对于单核单 CPU,CPU 负载为 0 表示 CPU 完全空闲,CPU 负载为 1.00 表示 CPU 恰好发挥其最大能力,CPU 负载大于 1 表示系统过载,有进程正在等待调度
  • 对于多核或者多 CPU 系统,CPU 负载为每个核的 CPU 负载总和

关于 CPU 负载的计算机制,可以参考我的另一篇博客

内存

free命令通过读取 /proc/meminfo,可以显示系统中的使用的和空闲的物理内存、Swap 内存,同时也可以显示内核使用的 buffer 和 cache,如下图所示。

1
2
3
4
$ free -w
              total        used        free      shared     buffers       cache   available
Mem:        7773244      311800     2456280         872      233560     4771604     7169352
Swap:             0           0           0

其中各个字段意义为:

  • total:所有可以使用的内存(包括/proc/meminfo 中的 MemTotal 和 SwapTotal)
  • used:使用的内存,通过 total - free - buffers - cache 计算得到
  • free:没有使用的内存(包括/proc/meminfo 中的 MemFree 和 SwapFree)
  • shared:主要是指 tmpfs 使用的内存,现在已经废弃不用,总是为 0
  • buffers:被内核 Buffers 使用的内存
  • cache:被内核的 Page Cache 和 Slab 使用的内存
  • buff/cache:buffers 和 cache 的总和
  • available:对于开启一个新的应用还能使用多少内存的估计,不同于 cache 和 free 内存外,还考虑了 page cache 和可再回收的 slab 内存

磁盘 IO

可以通过 iostat命令来监测磁盘的 IO 活动,它通过读取 /proc/diskstats文件来获取相关信息。

1
2
# cat /proc/diskstats
3    0   hda 446216 784926 9550688 4382310 424847 312726 5922052 19310380 0 3376340 23705160 0 0 0 0

hda 后的各个参数含义如下:

Field  1 -- # of reads completed
Field  2 -- # of reads merged, field 6 -- # of writes merged
	为了提高IO的效率,两个相邻的读写操作会被合并,所以两个4K的读操作在提交给磁盘之前会被合并为一个8K的读操作,杜宇磁盘来说只会视作只有一个读操作。
Field  3 -- # of sectors read
Field  4 -- # of milliseconds spent reading
Field  5 -- # of writes completed
Field  6 -- # of writes merged
Field  7 -- # of sectors written
Field  8 -- # of milliseconds spent writing
Field  9 -- # of I/Os currently in progress
Field 10 -- # of milliseconds spent doing I/Os
Field 12 -- # of discards completed
Field 13 -- # of discards merged
Field 14 -- # of sectors discarded
Field 15 -- # of milliseconds spent discarding

跟记录 CPU 信息的/proc/stat 文件一样,/proc/diskstats 中每个字段的数值也是从系统启动后一直累加的。通过这些参数,可以计算出通过 iostat命令算出的参数,具体可以参考iostat 。我们用 delta 来表示在时间 t 内某个字段的增量。例如定义 delta(reads merged)为当前 reads merged 的值减去 t 秒前 reads merged 的值

  • rrqm/s:delta(reads merged) / t (得到时间 t 内平均每秒 reads merged 的值)
  • wrqm/s:delta(writes merged) / t
  • r/s:delta(reads completed) / t
  • w/s:delta(writes completed) / t
  • rsec/s:delta(sectors read) / t
  • wsec/s:delta(sectors written) / t
  • rkB/s:delta(sectors read) / t / 2 (因为 1 扇区为 512 字节,所以 rkB/s 为 rsec/s 的一半)
  • wkB/s:delta(sectors written) / t / 2
  • avgrq-sz:(delta(sectors read) + delta(sectors written)) / (delta(reads completed) + delta(writes completed))
  • avgqu-sz:**delta(*weighted time spent doing I/Os*) / t / 1000 (单位为毫秒,所以除以 1000)
  • await:(delta(time spent reading) + delta(time spent writing)) / (delta(reads completed) + delta(writes completed))
  • **svctm:**delta(time spent doing I/Os)/ (delta(reads completed) + delta(writes completed))**
  • **%util:**delta(time spent doing I/Os) / t / 1000 * 100%

所有磁盘汇总采集项:

采集项 采集项说明 是否乘以 100 以保留精度
avgqu_sz_max 所有磁盘 avgqu_sz 最大值
svctm_time_max 所有磁盘 svctm 最大值
await_time_max 所有磁盘 await 最大值
util_max 所有磁盘%util 最大值
disk_total_read 所有磁盘的 r/s 总和
disk_total_write 所有磁盘的 w/s 总和
磁盘 IO disk_block_in 所有磁盘的 rkB/s 总和。bi 即 block in,表示从块设备(如磁盘)读取的块数。Linux 块设备的块大小都为 1024 字节,所以 disk_bi 等于 rkB/s。
磁盘 IO disk_block_out 所有磁盘的 rkB/s 总和 bo 即 block out,表示发给块设备的块数,即写磁盘。Linux 块设备的块大小都为 1024 字节,所以 disk_bi 等于 wkB/s。

单个磁盘采集项:

对于安装了 1 个以上的磁盘的服务器,可以采集单个磁盘的 IO 数据。最多支持 24 个盘。

采集项 采集项说明 是否乘以 100 以保留精度
disk_n_util(n 为 0-23) 第 n 个磁盘的%util 值
disk_n_await 第 n 个磁盘的 await 值
disk_n_read 第 n 个磁盘的 r/s 值
disk_n_write 第 n 个磁盘的 w/s 值
disk_n_block_in 第 n 个磁盘的 rkB/s 值
disk_n_block_out 第 n 个磁盘的 wkB/s 值

网络 IO

流量包量

通过 /proc/net/dev文件,可以计算出服务器的流量及包量。

1
2
3
4
5
6
# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:   69570    1756    0    0    0     0          0         0    69570    1756    0    0    0     0       0          0
  eth0: 2012939491 4197833    0    0    0     0          0         0 277523863 3280731    0    0    0     0       0          0
docker0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

与记录 CPU 信息的 /proc/stat文件类似,/proc/net/dev中的数值,也是从系统启动后一直累加的。

计算网卡流量方法如下:

  • 读取/proc/net/dev 文件,获取 eth0 的 Receive bytes、Receive packets、Transmit bytes、Transmit packets,分别记为 receive_bytes0、receive_packets0、transmit_bytes0、transmit_packets0
  • sleep 60 秒
  • 再次读取/proc/net/dev 文件,获取 eth0 的 Receive bytes、Receive packets、Transmit bytes、Transmit packets,分别记为 receive_bytes1、receive_packets1、transmit_bytes1、transmit_packets1
  • 根据 60 秒前后的/proc/net/dev 文件,便可计算出下面的指标:
    • 60 秒内平均每秒入流量:(receive_bytes1 - receive_bytes0) * 8 / 60 / 1000 (kbps)(乘以 8 是为了把 bytes 转成 bit,除以 1000 是为了把单位转成 k,除以 60 则是取 60 秒内的平均值)
    • 60 秒内平均每秒出流量:(transmit_bytes1 - transmit_bytes0) * 8 / 60 / 1000 (kbps)
    • 60 秒内平均每秒入包数:(receive_packets1 - receive_packets0) / 60 (个)
    • 60 秒内平均每秒出包数:(transmit_packets1 - transmit_packets0) / 60 (个)

TCP 连接数

/proc/net/snmp记录了一些 TCP 信息,其中比较有用的是 CurrEstab字段,即当前已建立的 TCP 连接数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# cat /proc/net/snmp
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 1 64 3527912 0 23 1893737 0 0 1634151 3266670 18 40 0 0 0 0 0 0 0
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 92566 32 0 65 0 0 0 0 92501 0 0 0 0 0 93265 0 746 0 0 0 18 0 92501 0 0 0 0
IcmpMsg: InType3 InType8 OutType0 OutType3 OutType5
IcmpMsg: 65 92501 92501 746 18
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 65567 687 59 249 8 1516787 1268763 805 4 33191 4
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
Udp: 22034 822 0 21968 0 0 0 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
UdpLite: 0 0 0 0 0 0 0 0

UDP 接收和发送数据报

/proc/net/snmp还记录了一些 UDP 信息,其中比较有用的是 InDatagramsOutDatagrams字段。

UDP 接收和发送数据报计算方法与 /proc/net/dev类似,步骤如下:

  • 读取/proc/net/snmp 得到 InDatagrams 及 OutDatagrams,分别记为 in_data0 和 out_data0
  • Sleep 240 秒
  • 再次读取/proc/net/snmp 得到 InDatagrams 及 OutDatagrams,分别记为 in_data1 和 out_data1
  • 根据 240 秒前后的/proc/net/snmp 文件,便可计算下面两个指标:
    • 240 秒内平均每秒 UDP 入数据报:(in_data1 - in_data0) / 240
    • 240 秒内平均每秒 UDP 出数据报:(out_data1 - out_data0) / 240
  • UDP 数据每 240 上报一次。

参考资料