案例五、监控磁盘使用率

对于磁盘的监控属于最基础的监控,但是很多时候往往因为运维的疏忽而忽略监控磁盘,最终导致事故发生。希望读到这篇文章的朋友,一定要把监控磁盘这件事重视起来。

本案例需求如下:

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


猜你喜欢

转载自blog.51cto.com/13576245/2422097