摘要:监控系统在linux系统上获取物理磁盘IO以及使用情况的原理,让我们一起来探索一下
本文使用语言为c++
第一步要解决的问题是先识别物理磁盘是哪些。
/proc/diskstats
的文件内容部分截取,我们可以通过读取/proc/diskstats
获得物理磁盘列表以确认哪些是物理设备(算云硬盘)以及iops等信息那这个文件内如此多的设备哪些是物理硬盘呢?只要达到下面两个限制条件就判定为物理硬盘。
sscanf
取到设备名/sys/block/设备名/device
,然后看此文件夹是否存在,如果存在则是物理磁盘设备access(syspath, F_OK)
,存在返回0/
的话要转换成!
,如下 while ((slash = strchr(name, '/'))) {
*slash = '!';
}
/sys/block
下的所有子目录代表着系统中当前被发现的所有块设备(其中的内容已经变为了指向它们在/sys/devices/中真实设备的符号链接文件)到此我们就取到了物理硬盘的iops,接下来我们来看看使用情况和总量是如何拿到的。
因为我们没有办法直接取到物理硬盘的使用情况,所以我们用一种间接的方式。根据分区和物理硬盘的关系获得物理硬盘的使用情况。比如一个物理硬盘sda
分了sda1 sda2
等两个分区,又知道sda1
的挂载点是/data
,sda2
的挂载点是/home
,通过某种方式查出/data
和home
的使用情况,加起来就是sda
的使用情况了。
我们可以,然后再通过获取挂载点大小的方式知道这些设备的使用情况。/etc/mtab
中不会直接物理硬盘的信息,所以只能通过把属于这个物理硬盘的全部分区加起来才能最后算出我们想要的值。
/etc/mtab
的方式拿到各种设备和它的挂载点。(/etc/mtab
文件中不会直接给出物理硬盘的使用情况)statfs
获得所挂载的目录使用情况来确定每个设备的使用情况 /dev/sda
是/dev/sda1
的子串)tips: 物理磁盘设备的名称列表我们已经在上一节取到了。
/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; /* 文件名的最大长度 */
};
返回说明:
计算分区的使用情况
#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;
/dev/root
设备可以从/proc/cmdline
中获取到真实设备名rootfs
设备要忽略,此为根文件系统(内核启动时所mount的第一个文件系统)我们根据上面的逻辑可以取到正常一般情况下的part类型的分区使用量,加到物理硬盘中去;如上图,出现lvm格式分区的时候,/etc/mtab
中就没有sda2设备的信息,而且sda2也没有挂载在任意一个文件系统上。这个时候就要拿到sda2下面挂载的三个lvm分区的使用情况。下图是lsblk的输出结果:
可以看到上图中,有一个逻辑卷(dm-2),同时挂在sda2和sdb1上,这是怎么回事?这就要从lvm的概念开始讲起了。
什么是lvm分区?
LVM的重点是可以弹性调整文件系统的容量,并不是如RAID在于对文件的读写性能或是数据的可靠性上。LVM可以将多个物理分区整合在一起,让这些分区看起来就像是一个磁盘一样,而且,还可以在将来添加其他的物理分区或将其从这个LVM管理的磁盘中删除。这样一来,整个硬盘的空间使用上,相当具有弹性。
这里介绍三个概念:
我们知道了这些就够了,怎么计算lvm格式的使用量并规到物理硬盘上呢?
我们要知道他的写入方式,才能知道算法。lvm有两种写入方式
LVM写入方式:
如何取到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分区,以下是核心代码
fd = open(deviceName.c_str(), O_RDONLY);
ret = ioctl(fd, BLKGETSIZE64, &size);
close(fd);
CalRound(size,M);
NAS(Network Attached Storage:网络附属存储)按字面简单说就是连接在网络上,具备资料存储功能的装置,因此也称为“网络存储器”。它是一种专用数据存储服务器。它以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。
nas硬盘,采集的时候当作逻辑磁盘,不是物理硬盘,他是共享的,多个用户共享一块nas盘的时候可以共享数据,所以nas盘不应该统计成物理磁盘,我们这里就没有算作,可以算作逻辑分区,直接在/etc/mtab
里就能读到啦。
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有什么区别
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。