linux系统 物理硬盘监控

摘要:监控系统在linux系统上获取物理磁盘IO以及使用状况的原理,让咱们一块儿来探索一下html

本文使用语言为c++
复制代码

本文原创首发于腾讯云+社区:linux系统 物理硬盘监控linux

物理磁盘列表和磁盘IO

第一步要解决的问题是先识别物理磁盘是哪些。c++

/proc/diskstats

  • 上图是/proc/diskstats的文件内容部分截取,咱们能够经过读取/proc/diskstats得到物理磁盘列表以确认哪些是物理设备(算云硬盘)以及iops等信息
  • 1-5列:设备号、编号、设备、读完成次数、合并完成次数
  • 6-10列:读扇区次数、读操做花费毫秒数、写完成次数、合并写完成次数、写扇区次数
  • 11-14列:写操做花费的毫秒数、正在处理的输入/输出请求数、输入/输出操做花费的毫秒数、输入/输出操做花费的加权毫秒数。

那这个文件内如此多的设备哪些是物理硬盘呢?只要达到下面两个限制条件就断定为物理硬盘。算法

  1. 该行有14列,可使用sscanf取到设备名
  2. 此行中的设备名组装成/sys/block/设备名/device,而后看此文件夹是否存在,若是存在则是物理磁盘设备
  • 备注1:判断文件/文件夹是否存在使用函数access(syspath, F_OK),存在返回0api

  • 备注2:若是设备名为中含有/的话要转换成!,以下服务器

while ((slash = strchr(name, '/'))) {
   *slash = '!';
  }
复制代码
  • 备注3:目录/sys/block下的全部子目录表明着系统中当前被发现的全部块设备(其中的内容已经变为了指向它们在/sys/devices/中真实设备的符号连接文件)

到此咱们就取到了物理硬盘的iops,接下来咱们来看看使用状况和总量是如何拿到的。网络

物理磁盘使用状况 和总量

物理磁盘使用量

由于咱们没有办法直接取到物理硬盘的使用状况,因此咱们用一种间接的方式。根据分区和物理硬盘的关系得到物理硬盘的使用状况。好比一个物理硬盘sda分了sda1 sda2等两个分区,又知道sda1的挂载点是/data,sda2的挂载点是/home,经过某种方式查出/datahome的使用状况,加起来就是sda的使用状况了。架构

咱们能够,而后再经过获取挂载点大小的方式知道这些设备的使用状况。/etc/mtab中不会直接物理硬盘的信息,因此只能经过把属于这个物理硬盘的所有分区加起来才能最后算出咱们想要的值。函数

使用状况计算逻辑

  • 经过读/etc/mtab的方式拿到各类设备和它的挂载点。(/etc/mtab文件中不会直接给出物理硬盘的使用状况)
  • 使用statfs得到所挂载的目录使用状况来肯定每一个设备的使用状况
  • 根据分区和物理硬盘的关系得到物理硬盘的使用状况(一般物理磁盘的名称是分区的子串,好比/dev/sda/dev/sda1的子串)

tips: 物理磁盘设备的名称列表咱们已经在上一节取到了。性能

经过/etc/mtab文件拿到各类设备和它的挂载点

知道了计算逻辑,咱们来看看/etc/mtab文件内容的含义

/etc/mtab

  • 上图是/etc/mtab的内容截取,能够读取/etc/mtab文件获取设备名和挂载点
  • 此文件每行有四列,分别表明的含义是:驱动器、挂载点、文件系统、读写权限
  • /etc/mtab记载了当前系统已经装载的文件系统,包括一些操做系统虚拟文件,使用/etc/fstab也能够监控,不一样的是/etc/mtab文件在mount挂载、umount卸载时都会被更新,时刻跟踪当前系统中的分区挂载状况。

用到了如下核心c++函数(读取/etc/mtab)

mount_table = setmntent("/etc/mtab", "r"); //打开文件系统描述文件的文件名,而且返回能够被使用的文件指针getmntent().
mount_entry = getmntent(mount_table);//函数读取文件系统的下一行来自文件流的描述文件并返回指向结构的指针(即循环读取文件)
device = mount_entry->mnt_fsname;
mount_point = mount_entry->mnt_dir;
statfs(mount_point, &s) != 0 //此条件成立时获取成功
endmntent(mount_table);//关闭流和与其相关联的文件系统描述文件。
复制代码

具体用法见 linux中getmntent、setmntent 、endmntent 函数的详细用法

经过statfs函数所挂载的目录使用状况(used/total)来肯定每一个分区的使用状况

#include <sys/vfs.h> /* 或者 <sys/statfs.h> */

// path: 须要查询信息的文件系统的文件路径名。 如/home
// buf:如下结构体的指针变量,用于储存文件系统相关的信息
int statfs(const char *path, struct statfs *buf); 
// fd: 须要查询信息的文件系统的文件描述词。
int fstatfs(int fd, struct statfs *buf);


struct statfs { 
   long    f_type;     /* 文件系统类型 */ 
   long    f_bsize;    /* 通过优化的传输块大小 */ 
   long    f_blocks;   /* 文件系统数据块总数 */ 
   long    f_bfree;    /* 可用块数 */ 
   long    f_bavail;   /* 非超级用户可获取的块数 */ 
   long    f_files;    /* 文件结点总数 */ 
   long    f_ffree;    /* 可用文件结点数 */ 
   fsid_t  f_fsid;     /* 文件系统标识 */ 
   long    f_namelen;  /* 文件名的最大长度 */ 
}; 
复制代码

返回说明:

  • 成功执行时,返回0。失败返回-1
  • statfs结构中可用空间块数有两种f_bfree和 f_bavail,前者是硬盘全部剩余空间,后者为非root用户剩余空间,ext3文件系统给root用户分有5%的独享空间,因此这里是不一样的地方。这里要强调的是每块的大小通常是4K(×这句话错误,不必定都是4k,正确作法是:总大小=sfs.f_blocks×f_bsize,即块数×每块的大小,单位是bytes,也就是要/1024/1024/1024才是GB单位)。

计算分区的使用状况

#define M (1024*1024)

    blocks_used = s.f_blocks - s.f_bfree; //使用量

    blocks_percent_used = 0;

    if (blocks_used + s.f_bavail) 

    {

     blocks_percent_used = blocks_used * 100 / (blocks_used + s.f_bavail); //使用率

    }

    /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */

    if (strcmp(device, "rootfs") == 0)

     continue;

    Record record;

    record.disk_total_val = CalRound((blocks_used + s.f_bavail) * s.f_bsize, M); //总量

    record.disk_use_val = CalRound((s.f_blocks - s.f_bfree) * s.f_bsize, M);  //

    record.use_precent = blocks_percent_used;

复制代码
  • CalRound函数的做用是四舍五入,感兴趣能够拉到文章底部看代码。
  • 在获取使用量状况失败的时候,多是由于没有挂载获取其余特殊的状况,咱们就默认使用量为0
  • 备注1:/dev/root设备能够从/proc/cmdline中获取到真实设备名

  • 备注2:rootfs设备要忽略,此为根文件系统(内核启动时所mount的第一个文件系统)

若是出现lvm格式的逻辑分区怎么计算使用量?

咱们根据上面的逻辑能够取到正常通常状况下的part类型的分区使用量,加到物理硬盘中去;如上图,出现lvm格式分区的时候, /etc/mtab中就没有sda2设备的信息,并且sda2也没有挂载在任意一个文件系统上。这个时候就要拿到sda2下面挂载的三个lvm分区的使用状况。下图是lsblk的输出结果:

能够看到上图中,有一个逻辑卷(dm-2),同时挂在sda2和sdb1上,这是怎么回事?这就要从lvm的概念开始讲起了。

什么是lvm分区?

LVM的重点是能够弹性调整文件系统的容量,并非如RAID在于对文件的读写性能或是数据的可靠性上。LVM能够将多个物理分区整合在一块儿,让这些分区看起来就像是一个磁盘同样,并且,还能够在未来添加其余的物理分区或将其从这个LVM管理的磁盘中删除。这样一来,整个硬盘的空间使用上,至关具备弹性。

pv vg lv架构

这里介绍三个概念:

  • PV(physical volume):物理卷在逻辑卷管理系统最底层,可为整个物理硬盘或实际物理硬盘上的分区。
  • VG(volume group):卷组创建在物理卷上,一卷组中至少要包括一物理卷,卷组创建后可动态的添加卷到卷组中,一个逻辑卷管理系统工程中可有多个卷组。
  • LV(logical volume):逻辑卷创建在卷组基础上,卷组中未分配空间可用于创建新的逻辑卷,逻辑卷创建后能够动态扩展和缩小空间。

咱们知道了这些就够了,怎么计算lvm格式的使用量并规到物理硬盘上呢? 咱们要知道他的写入方式,才能知道算法。lvm有两种写入方式

LVM写入方式:

  • 线性模式(linear):假若有/dev/sdb1,/dev/sdb2这2个分区加入到VG当中,而且整个VG只有一个LV时,那么所谓的线性模式就是当/dev/sdb1的容量用完以后,/dev/sdb2的分区才会被使用。在此模式下,使用量就按顺序算到所挂的分区上去。
  • 交错模式(triped):将一条数据拆分红两部分,分别写入/dev/sdb1与/dev/sdb2,有点像RAID0。这样子,一份数据用两块硬盘来写入,理论上,读写性能会比较好。在此模式下,使用量就按平均到所挂的分区上去,可能会有点细微的差异,但这是相对准确的方式了。

如何取到lvm类型

执行lvm相关的命令以前必需要安装lvm2这个软件,不过CentOS和其余比较新的Linux发行版已经默认安装了lvm的所需软件,况且咱们这里的目的是监控已经建立lvm分区的linux机器(lsblk看到的),那必定有这些软件,就不用担忧这个问题了。

可是比较老的版本没有这些参数,好比

那咱们用这种方式

ps:直接解析 /proc/swaps的内容有同样的效果哦

如今咱们取到了dm-1设备的使用状况和总量,正常来讲能够结合lsblk的结果和对应到磁盘上,可是问题来了,有的lsblk输出结果不带有dm-1这种字样,那怎么办呢?

不用怕,咱们能够利用VG和LV的名称找到他们的软连接(符号连接)。再用c++的readlink函数取到符号连接所指向的文件

ps: 你们能够看到,这里的lvm使用量都是用命令方式来采集的,若是你有读文件或者系统api等更好的方式,但愿你能够留言和我交流,很是感谢!

物理磁盘总量

咱们能够直接根据磁盘名(好比/dev/sda)来获取磁盘总量,不管是否有lvm分区,如下是核心代码

unsigned long long AgentDiskRpt::readDiskTotal(const string &deviceName)
 {
  int fd, ret;
  unsigned long long size;

  fd = open(deviceName.c_str(), O_RDONLY);

  if (fd == -1)
  {
   close(fd);
   return -1;
  }
  ret = ioctl(fd, BLKGETSIZE64, &size);

  if (ret == 0) {
   close(fd);
      return CalRound(size,M);
  }
  close(fd);
  return 0;
 }
复制代码

遇到nas硬盘怎么计算?

NAS(Network Attached Storage:网络附属存储)按字面简单说就是链接在网络上,具有资料存储功能的装置,所以也称为“网络存储器”。它是一种专用数据存储服务器。它以数据为中心,将存储设备与服务器完全分离,集中管理数据,从而释放带宽、提升性能、下降总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。

nas硬盘,采集的时候看成逻辑磁盘,不是物理硬盘,他是共享的,多个用户共享一块nas盘的时候能够共享数据,因此nas盘不该该统计成物理磁盘,咱们这里就没有算做,能够算做逻辑分区,直接在/etc/mtab里就能读到啦。

其余

CalRound函数

unsigned long long CalRound(unsigned long long value, int base) {
  unsigned long long ret = 0;
  if (base <= 1)
   return value;
  unsigned long long tmp = base / 2;
  if (tmp <= 0)
   tmp = 1;
  if (value % base >= tmp)
   ret = value / base + 1;
  else
   ret = value / base;
  return ret;
 }
复制代码

参考

Linux /etc/fstab和etc/mtab有什么区别

statfs

linux中getmntent、setmntent 、endmntent 函数的详细用法

LVM动态逻辑卷理论详解

相关文章
相关标签/搜索