the site subtitle

procfs 与 Linux 系统监控

2019.08.25

Unix系推崇一个观点,Everything is a file 。对于一些系统以及进程信息,kernel会以文件系统的系统挂载在proc和sys目录,也就是常说的procfs,sysfs虚拟文件系统。包括CPU,内存和硬盘等信息。当然对于系统监控来说,这也是重要的数据源。

proc的目录看起来是下面这样的,那些数字都是进程的PID,其他的是一些系统系,比如cpuinfo记录者硬件的CPU信息:

接下来我们看一下进程PID里面的信息,记录者此进程的启动命令,参数等信息。

ls /proc/
1     1170  1345  19    2116   304  382  406  787  942        consoles     interrupts   kpageflags  pagetypeinfo  sysrq-trigger
10    12    14    1911  22     305  383  408  8    955        cpuinfo      iomem        loadavg     partitions    sysvipc
1022  1205  15    1922  24     31   384  41   824  96         crypto       ioports      locks       sched_debug   thread-self
105   1215  16    1928  25     32   387  42   85   967        devices      irq          mdstat      schedstat     timer_list
1059  1216  174   2     257    33   389  422  86   979        diskstats    kallsyms     meminfo     scsi          tty
11    122   175   20    26     34   398  462  87   994        dma          kcore        misc        self          uptime
1122  1243  176   2098  26150  35   4    555  88   acpi       driver       key-users    modules     slabinfo      version
1134  1269  177   21    27     36   40   556  89   buddyinfo  execdomains  keys         mounts      softirqs      version_signature
1147  1289  18    2100  28     37   400  6    9    bus        fb           kmsg         mpt         stat          vmallocinfo
1152  13    183   2114  29     379  402  639  90   cgroups    filesystems  kpagecgroup  mtrr        swaps         vmstat
1166  1340  186   2115  30     381  404  7    908  cmdline    fs           kpagecount   net         sys           zoneinfo


ls /proc/1/
attr        cmdline          environ  io         mem         ns             pagemap      sched      smaps_rollup  syscall        wchan
autogroup   comm             exe      limits     mountinfo   numa_maps      patch_state  schedstat  stack         task
auxv        coredump_filter  fd       loginuid   mounts      oom_adj        personality  sessionid  stat          timers
cgroup      cpuset           fdinfo   map_files  mountstats  oom_score      projid_map   setgroups  statm         timerslack_ns
clear_refs  cwd              gid_map  maps       net         oom_score_adj  root         smaps      status        uid_map

sysfs主要记录的系统的设备信息,如果是一个docker0的虚拟网卡:

ls /sys/devices/virtual/net/docker0/
addr_assign_type  bridge     carrier_changes     dev_port  gro_flush_timeout  link_mode         operstate       power       statistics    uevent
addr_len          brif       carrier_down_count  dormant   ifalias            mtu               phys_port_id    proto_down  subsystem
address           broadcast  carrier_up_count    duplex    ifindex            name_assign_type  phys_port_name  queues      tx_queue_len
brforward         carrier    dev_id              flags     iflink             netdev_group      phys_switch_id  speed       type

刚才上面已经提到procfs是监控系统重要的数据源之一,接下来用几个实例来说明如何监控这些资源。

CPU

我们经常说机器的CPU又到95%了,是不是又被挖矿了?那么这个95%又是怎么计算的呢?其实这些东西在top的手册都写的有,首先我们先看一下top中对于CPU使用率的定义,最后的那个单词很关键CPU time(本文不关注Linux如何对进程的分配CPU时间), kernel会把进程的CPU time写到/proc/{PID}/stat/这个文件中,。

 %CPU  --  CPU Usage
The task's share of the elapsed CPU time since the last screen update, expressed as a percentage of total CPU time.

下面是dockerd进程的数据示例:

1242 (dockerd) S 1 1242 1242 0 -1 1077936384 36414 247979 270 69 7206 4167 806 875 20 0 14 0 1412 1133367296 18712 18446744073709551615 94364227485696 94364275405412 140725279924976 0 0 0 1006249984 0 2143420159 0 0 0 17 1 0 0 92 0 0 94364277503464 94364298771328 94364323065856 140725279932063 140725279932150 140725279932150 140725279932391 0

然后我们写一个很耗CPU的进程,就是死循环啦,它会使某个CPU的使用率达到100%,接受的参数为CPU个数,输出死循环的进程pid,注意在Linux系统中,top显示的CPU使用率和核心数相关,也就是双核的机器最高是200%。

#! /bin/sh
if [ $# != 1 ] ; then
  echo "USAGE: $0 <CPUs>"
  exit 1;
fi
for i in `seq $1`; do
  echo -ne "i=0;while true;do i=i+1;
done" | /bin/sh &
  pid_array[$i]=$! ;
done
# 输出pid
for i in "${pid_array[@]}"; do
  echo 'kill ' $i ';';
done

根据上面的文档写一个计算CPU使用率的脚本,与top显示的进行对比,计算公式注释已经说明了。

pid=9548
# 输出top计算的与后面进行对比
top -b -n 1 -p $pid  2>&1 | awk -v pid=$pid '{if ($1 == pid)print $9}'

# 找出CPU数目
cpu_core=$(grep -c processor /proc/cpuinfo)

# 0秒时的CPU时间
total_time1=$(awk '{if ($1 == "cpu") {sum = $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10 + $11;print sum}}' /proc/stat)
cpu_time1=$(awk '{sum=$14 + $15;print sum}' /proc/$pid/stat)
# 1秒后的CPU时间
sleep 1
total_time2=$(awk '{if ($1 == "cpu") {sum = $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10 + $11;print sum}}' /proc/stat)
cpu_time2=$(awk '{sum=$14 + $15;print sum}' /proc/$pid/stat)
# (进程CPU时间差)处以 系统总CPU时间差 乘以CPU个数
awk -v cpu_time1=$cpu_time1 -v total_time1=$total_time1 -v cpu_time2=$cpu_time2 -v total_time2=$total_time2 -v cpu_core=$cpu_core \
'BEGIN{cpu=((cpu_time2 - cpu_time1) / (total_time2 - total_time1)) * 100*cpu_core;print cpu}'

Memory

对于内存来说经常使用的命令也就是free ,那么它读取的就是这里/proc/meminfo,例如free命令的输出

free -mh
              total        used        free      shared  buff/cache   available
Mem:           1.9G        212M        133M        956K        1.6G        1.6G
Swap:            0B          0B          0B

其中部分数据如下:

cat /proc/meminfo
MemTotal:        2041120 kB
MemFree:          131632 kB
MemAvailable:    1635632 kB
Buffers:          257304 kB
Cached:          1220788 kB
SwapCached:            0 kB
Active:           914556 kB

Network

对于网络的监控,不仅有网卡的说句,还是TCP UDP等的数据。其中网卡数据主要来源于/proc/net/dev

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:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
enp0s3: 655272901  547097    0    0    0     0          0         0  8184738  111064    0    0    0     0       0          0
enp0s8:   38372     393    0    0    0     0          0         2     1846      25    0    0    0     0       0          0
docker0:  210438    4999    0    0    0     0          0         0 25782544    5340    0    0    0     0       0          0
br-4ef817c04403:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
root@ubuntu-bionic:/home/vagrant#

下面是一个通过读取此文件然后输出对应网卡流量的脚本:

#!/bin/bash
usage() {
        echo "Useage : $0"
        echo "eg. sh $0 eth0 2"
        exit 1
}
if [ $# -lt 2 ]
then
        usage
fi
eth=$1
timer=$2
in_old=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $1 }')
out_old=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $9 }')
while true
do
        sleep ${timer}
        in=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $1 }')
        out=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $9 }')
        dif_in=$(((in-in_old)/timer))
        dif_in=$((dif_in/1024))
        dif_out=$(((out-out_old)/timer))
        dif_out=$((dif_out/1024))
        ct=$(date +"%F %H:%M:%S")
        echo "${ct} -- IN: ${dif_in} KByte/s     OUT: ${dif_out} KByte/s"
        in_old=${in}
        out_old=${out}
done
exit 0

Ref

CPU使用率原理及计算方式

https://www.cnblogs.com/gatsby123/p/11127158.html

PROCFS AND SYSFS

https://landoflinux.com/linux_procfs_sysfs.html