案例五、監控磁盤使用率

對於磁盤的監控屬於最基礎的監控,但是很多時候往往因爲運維的疏忽而忽略監控磁盤,最終導致事故發生。希望讀到這篇文章的朋友,一定要把監控磁盤這件事重視起來。

本案例需求如下:

1)每分鐘檢測一次磁盤狀況

2)當磁盤空間使用率或者iNode使用率高於90%,需要發郵件告警,假設收件郵箱爲[email protected]

3)統計使用率超過90%的分區所有子目錄的大小,並把排名前三的子目錄寫到郵件內容中發給上面的郵箱

4)第一次告警後,如果我們沒有及時處理,則需要每隔30分鐘告警一次

5)每分鐘腳本執行時,需檢測該腳本是否已執行完,如果沒有完成則本次不執行


知識點一:查看磁盤使用

命令:df

df查看已掛載磁盤的總容量、使用容量、剩餘容量等,可以不加任何參數,默認是以k爲單位顯示的,常用選項有-i,-h,-k,-m。-i選項查看iNode使用狀況,-h選項會使用合適的單位顯示,例如G或M,-k、-m選項分別以K、M爲單位顯示。

# df -h
文件系統        容量  已用  可用 已用% 掛載點
/dev/sda3        16G  8.0G  7.9G   51% /
devtmpfs        903M     0  903M    0% /dev
tmpfs           912M     0  912M    0% /dev/shm
tmpfs           912M  8.7M  903M    1% /run
tmpfs           912M     0  912M    0% /sys/fs/cgroup
/dev/sda1       197M  113M   85M   58% /boot
tmpfs           183M     0  183M    0% /run/user/0

第一列是分區名字,第二列爲該分區總共的容量,第三列爲已經使用了多少,第四列爲還剩下多少,第五列爲已經使用的百分比,最後一列爲掛載點。


知識點二:查看目錄或文件大小

命令:du

du命令用來查看某個目錄或文件所佔空間的大小。

語法:du [-abckmsh] [文件名或目錄名]

常用參數:

-a:表示全部文件和目錄的大小都列出來。若後面不加任何選項和參數。則只會列出目錄(包含子目錄)的大小。若du命令不指定單位的話,默認顯示單位爲KB。

示例命令:

# du /tmp/test
0	/tmp/test
# du -a /tmp/test
0	/tmp/test/1.txt
0	/tmp/test

-b:表示列出的值以B爲單位輸出。

-k:表示以KB爲單位輸出,這和默認不加任何選項的輸出值是一樣的。

-m:表示以MB爲單位輸出。

-h:表示系統自動調節單位。

-c:表示最後加總。不常用,示例命令:

# du -c /tmp/test
0	/tmp/test
0	總用量

-s:表示只列出總和。常用選項,示例命令:

# du -s /tmp/test
0	/tmp/test


常用的用法:du -sh filename


結合find查找某個目錄下所有子目錄,並統計大小,命令爲:

# find /dir/ -type d |sed '1d' |xargs du -sm

說明:用sed '1d'刪除第一行,原因是第一行是目錄本身,而我們要統計的是子目錄。


知識點三:查看進程

在Windows下可以進入任務管理器查看進程,在Linux下有一些命令也可以查看進程。

1)top

這個命令用於動態監控進程所佔系統資源,每隔3秒變一次。該命令的特點是把佔用系統資源(CPU、內存、磁盤IO等)最高的進程放到最前面。

top命令打印出了很多信息,包括系統負載(load average)、進程數(Tasks)、CPU使用情況、內存使用情況以及交換分區使用情況。

top重點查看的還是下面的進程使用系統資源詳細情況。這部分東西反映的還是比較多,不過需要關注的也就幾項:RES,%CPU,%MEN,COMMAND。RES爲進程所佔內存大小,%CPU爲進程使用CPU百分比。COMMAND爲具體進程名字。

在top狀態下,按M可按內存使用大小排序,按P切回CPU排序,按數字1可列出每顆CPU的使用狀態。常用的一個命令爲:top -bn1,表示靜態打印系統資源使用情況,適合用在shell腳本中。top還有一個-c選項,可以顯示具體的命令,也就是說在COMMAND這一列出更加詳細。

2)ps

ps命令用來彙報當前系統進程的狀況,常見用法有ps aux和ps -elf。

在本例中,我們檢查某個進程是否存在,可以用:

# ps aux |grep '進程名'

假如,本腳本的名字爲mon_disk.sh,則需要這樣統計:

# ps aux |grep 'mon_disk.sh' |grep -vE "$$|grep"

說明:這裏的$$爲本進程PID ,之所以要排除掉它,是因爲我們需要檢查之前的舊進程而不是本次的進程,並且需要把grep這個進程也排除掉。


知識點四:告警收斂思路分析

本案例中有要求,如果發生告警後,下次再告警應該是30分鐘後。腳本本應該是一分鐘執行一次,告警郵件也會一分鐘發一次,告警郵件也會一分鐘發一次,如果我們不能在短時間內修復完問題,則會造成郵件騷擾。

這裏的思路是引入一個計數器,而且需要考慮以下幾個場景:

1)腳本從來沒有告警過,第一次告警

這種情況,不用考慮太多東西,直接發郵件,但需要做兩件事,第一需要記錄此時的時間戳到一個臨時文件中,第二需要建立一個臨時文件記錄告警次數,告警發生但不一定發郵件,要區分差異。

2)腳本之前告警過,距離上一次告警超過30分鐘

判斷距離上一次告警多久需要藉助記錄時間戳的臨時文件,求本次告警時間戳和上一次告警時間戳的差值,是否大於1800秒。根據需求,只要大於30分鐘就可以立即發郵件,同時記錄時間戳和告警次數到兩個不同的臨時文件中。

3)腳本之前告警過,距離上一次告警不超過30分鐘

不超過30分鐘則需要查看記錄告警次數的臨時文件,只有次數大於等於30纔會再一次發郵件。


本案例參考腳本

#!/bin/bash
##監控磁盤使用情況,並做告警收斂(30分鐘發一次郵件)
##作者:
##日期:
##版本:v0.1

#把腳本名字存入變量s_name
s_name=`echo $0 |awk -F '/' '{print $NF}'`
#定義收件人郵箱
[email protected]

#定義檢查磁盤空間使用率函數
chk_sp()
{
  df -m |sed '1d' |awk -F '%| +' '$5>90 {print $7,$5}'>/tmp/chk_sp.log
  n=`wc -l /tmp/chk_sp.log|awk '{print $1}'`
  if [ $n -gt 0 ]
  then
      tag=1
      for d in `awk '{print $1}' /tmp/chk_sp.log`
      do
        find $d -type d |sed '1d' |xargs du -sm |sort -nr|head -3
      done > /tmp/most_sp.txt
  fi
}

#定義檢查iNode使用率的函數
chk_in()
{
  df -i |sed '1d'|awk -F '%| +' '$5>90 {print $7,$5}'>/tmp/chk_in.log
  n=`wc -l /tmp/chk_in.log|awk '{print $1}'`
  if [ $n -gt 0 ]
  then
      tag=2
  fi
}

#定義告警函數(這裏的mail.py是案例二中的那個腳本)
m_mail(){
   log=$1  #此處的$1表示第一個函數chk_sp
   t_s=`date +%s`
   t_s2=`date -d "1 hours ago" +%s`
   if [ ! -f /tmp/$log ]
   then
       #創建$log文件
       touch /tmp/$log
       #增加a權限,只允許追加內容,不允許更改或刪除
       chattr +a /tmp/$log
       #第一次告警,可以直接寫入1小時以前的時間戳
       echo $t_s2 >> /tmp/$log
   fi
   #無論$log文件是否是剛剛創建,都需要查看最後一行的時間戳
   t_s2=`tail -1 /tmp/$log|awk '{print $1}'`
   #取出最後一行即上次告警的時間戳後,立即寫入當前的時間戳
   echo $t_s>>/tmp/$log
   #取兩次時間戳差值
   v=$[$t_s-$t_s2]
   #如果差值超過1800,立即發郵件
   if [ $v -gt 1800 ]
   then
      #發郵件,其中$2爲mail函數的第二個參數,這裏爲一個文件
      python mail.py $mail_user "磁盤使用率超過90%" "`cat $2`" 2>/dev/null
      #定義計數器臨時文件,並寫入0
      echo "0" > /tmp/$log.count
   else
      #如果計數器臨時文件不存在,需要創建並寫入0
      if [ ! -f /tmp/$log.count ]
      then
          echo "0" > /tmp/$log.count
      fi
      nu=`cat /tmp/$log.count`
      #30分鐘內每發生一次告警,計數器加1
      nu2=$[$nu+1]
      echo $nu2>/tmp/$log.count
      #當告警次數超過30次,需要再次發郵件
      if [ $nu2 -gt 30 ]
      then
          python mail.py $mail_user "磁盤使用率超過90%持續30分鐘了" "`cat $2`" 2>/dev/null
          #第二次告警後,將計數器再次從0開始
          echo "0" > /tmp/$log.count
      fi
    fi
}

#把進程情況存入臨時文件,如果加管道求行數會有問題
ps aux |grep "$s_name" |grep -vE "$$|grep">/tmp/ps.tmp
p_n=`wc -l /tmp/ps.tmp|awk '{print $1}'`

#當進程數大於0,則說明上次的腳本還未執行完
if [ $p_n -gt 0 ]
then
    exit
fi

chk_sp
chk_in

if [ $tag == 1 ]
then
   m_mail chk_sp /tmp/most_sp.txt
elif [ $tag == 2 ]
then
   m_mail chk_in /tmp/chk_in.log
fi


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章