摘要:監控系統在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有什麼區別