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動態邏輯卷理論詳解

相關文章
相關標籤/搜索