摘要:监控系统在linux系统上获取物理磁盘IO以及使用状况的原理,让咱们一块儿来探索一下html
本文使用语言为c++
复制代码
本文原创首发于腾讯云+社区:linux系统 物理硬盘监控linux
第一步要解决的问题是先识别物理磁盘是哪些。c++
/proc/diskstats
的文件内容部分截取,咱们能够经过读取/proc/diskstats
得到物理磁盘列表以确认哪些是物理设备(算云硬盘)以及iops等信息那这个文件内如此多的设备哪些是物理硬盘呢?只要达到下面两个限制条件就断定为物理硬盘。算法
sscanf
取到设备名/sys/block/设备名/device
,而后看此文件夹是否存在,若是存在则是物理磁盘设备备注1:判断文件/文件夹是否存在使用函数access(syspath, F_OK)
,存在返回0api
备注2:若是设备名为中含有/
的话要转换成!
,以下服务器
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的第一个文件系统)/etc/mtab
中就没有sda2设备的信息,并且sda2也没有挂载在任意一个文件系统上。这个时候就要拿到sda2下面挂载的三个lvm分区的使用状况。下图是lsblk的输出结果:
什么是lvm分区?
LVM的重点是能够弹性调整文件系统的容量,并非如RAID在于对文件的读写性能或是数据的可靠性上。LVM能够将多个物理分区整合在一块儿,让这些分区看起来就像是一个磁盘同样,并且,还能够在未来添加其余的物理分区或将其从这个LVM管理的磁盘中删除。这样一来,整个硬盘的空间使用上,至关具备弹性。
这里介绍三个概念:
咱们知道了这些就够了,怎么计算lvm格式的使用量并规到物理硬盘上呢? 咱们要知道他的写入方式,才能知道算法。lvm有两种写入方式
LVM写入方式:
如何取到lvm类型
执行lvm相关的命令以前必需要安装lvm2这个软件,不过CentOS和其余比较新的Linux发行版已经默认安装了lvm的所需软件,况且咱们这里的目的是监控已经建立lvm分区的linux机器(lsblk看到的),那必定有这些软件,就不用担忧这个问题了。
/proc/swaps
的内容有同样的效果哦
如今咱们取到了dm-1设备的使用状况和总量,正常来讲能够结合lsblk的结果和对应到磁盘上,可是问题来了,有的lsblk输出结果不带有dm-1这种字样,那怎么办呢?
咱们能够直接根据磁盘名(好比/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(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有什么区别