貔貅云原生

貔貅云原生

iostat 分析

2024-04-29
iostat 分析

iostat 分析

需求

公司的磁盘监控项,需要 3 个监控指标分别为:io使用率、磁盘平均队列长度、磁盘读写平均延迟。通常的方法是查找有没有开源的对应 exporter 与计算表达式,但是这里的做法是提供了一个思路,让人换一种思考方式。

我们知道 iostat 命令可以全方面查看到系统磁盘状态,这里就是分析一下 sysstat 项目下的 iostat。分析它怎么实现的:io使用率、磁盘平均队列长度、磁盘读写平均延迟。

iostat 命令

使用 iostat -x 5 显示扩展状态,这里显示了磁盘状态,也显示了cpu状态,当然cpu状态我们不用关心,主要关系磁盘的几个指标:

标示说明
Device监测设备名称
rrqm/s每秒需要读取需求的数量
wrqm/s每秒需要写入需求的数量
r/s每秒实际读取需求的数量
w/s每秒实际写入需求的数量
rkB/s每秒实际读取的大小,单位为KB
wkB/s每秒实际写入的大小,单位为KB
avgrq-sz需求的平均大小区段
avgqu-sz每需求的平均队列长度
await等待I/O平均的时间
r_await读等待I/O平均的时间
w_await写等待I/O平均的时间
svctmI/O需求完成的平均时间
%util被I/O需求消耗的CPU百分比

在 iostat 中,它已经计算好了我们所需要的内容,比如 avgqu-sz,所以通常情况下我们只需要使用 iostat 命令获取指标就可以了,但是作为监控程序来讲最好的方式是不需要依赖其他命令执行,所以这里分析一下 avgqu-sz 实现原理。

[root@deploy network-scripts]# iostat -x 5
Linux 3.10.0-1160.el7.x86_64 (deploy)   04/29/2024      _x86_64_        (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.58    0.00    1.27    0.05    0.00   98.10

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
scd0              0.00     0.00    0.07    0.00     4.11     0.00   114.22     0.00    1.33    1.33    0.00   0.94   0.01
sda               0.02     0.12   27.60    1.33  1538.30    40.32   109.14     0.01    0.25    0.21    1.08   0.15   0.44
dm-0              0.00     0.00   19.52    1.44  1421.49    32.13   138.74     0.01    0.34    0.27    1.17   0.19   0.40

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.10    0.00    0.20    0.00    0.00   99.70

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sda               0.00     0.00    0.20    0.00     1.60     0.00    16.00     0.00    1.00    1.00    0.00   1.00   0.02
dm-0              0.00     0.00    0.20    0.00     1.60     0.00    16.00     0.00    1.00    1.00    0.00   1.00   0.02

avgqu-sz

sysstat项目 包含了非常多的系统方面的观测数据,这里 iostat 就是其中一个功能

# ./iostat.c:1235
# 在 iostat.c 中找到了它的计算表达式
# 具体解释为:一个三元运算符,用于比较 ioi 和 ioj 的值。如果 ioi 小于 ioj,则为0.0;否则,计算 S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0 的值。

/* aqu-sz */
  cprintf_f(NO_UNIT, FALSE, 1, 7, 2,
     ioi->rq_ticks < ioj->rq_ticks ? 0.0 :
     S_VALUE(ioj->rq_ticks, ioi->rq_ticks, itv) / 1000.0);
    ...

# 接下来该找一下 S_VALUE、rq_ticks、itv 分别是什么


# ./iostat.c:816
# 这里发现其实是读取的系统的某个文件,然后对每一行的数据进行分解并赋值
# 这里找到了 rq_ticks
# 那么读取的文件是根据上面注释提示的 /proc/diskstats

/*
 ***************************************************************************
 * Read stats from the diskstats file. Only used when "-p ALL" has been
 * entered on the command line.
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 * @diskstats	Path to diskstats file (e.g. "/proc/diskstats").
 ***************************************************************************
 */

if ((fp = fopen(diskstats, "r")) == NULL)
  return;

 while (fgets(line, sizeof(line), fp) != NULL) {

  memset(&sdev, 0, sizeof(struct io_stats));

  /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq dcio dcmerge dcsect dcuse flio fltm */
  i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u %lu %lu %lu %u %lu %u",
      &major, &minor, dev_name,
      &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
      &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
      &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
      &fl_ios, &fl_ticks);

  if (i >= 14) {
   sdev.rd_ios     = rd_ios;
   sdev.rd_merges  = rd_merges_or_rd_sec;
   sdev.rd_sectors = rd_sec_or_wr_ios;
   sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
   sdev.wr_ios     = wr_ios;
   sdev.wr_merges  = wr_merges;
   sdev.wr_sectors = wr_sec;
   sdev.wr_ticks   = wr_ticks;
   sdev.ios_pgr    = ios_pgr;
   sdev.tot_ticks  = tot_ticks;
   sdev.rq_ticks   = rq_ticks;
    ...

# ./common.c:776
# 这里计算 itv 时间,通过翻译大致知道 itv 当前时间 - 之前时间,那么就应该是一个时间间隔
# 然后这里又说了值 1/100th of a second ,1秒的 100 分之 1,那么间隔默认应该是 10ms 为单位

/*
 ***************************************************************************
 * Compute time interval.
 *
 * IN:
 * @prev_uptime	Previous uptime value (in jiffies or 1/100th of a second).
 * @curr_uptime	Current uptime value (in jiffies or 1/100th of a second).
 *
 * RETURNS:
 * Interval of time in jiffies or 1/100th of a second.
 ***************************************************************************
 */
unsigned long long get_interval(unsigned long long prev_uptime,
    unsigned long long curr_uptime)
{
 unsigned long long itv;

 /* prev_time=0 when displaying stats since system startup */
 itv = curr_uptime - prev_uptime;

 if (!itv) { /* Paranoia checking */
  itv = 1;
 }

 return itv;
}


# ./common.h:163
# 这里找到了计算函数

/* With S_VALUE macro, the interval of time (@p) is given in 1/100th of a second */
#define S_VALUE(m,n,p)  (((double) ((n) - (m))) / (p) * 100)


# 如果我选择 5 秒采集一次文件的方法,那么根据多种分析总结出来表达式:(现在文件内容值 - 之前文件内容值) / (采集间隔 5 * 内部时间 10 毫秒) * 100

总结

简单的分析知道,iostat 信息依赖于文件,只是如何取的问题,其他磁盘监控指标,也可以通过阅读底层代码转成自己的逻辑实现。