Shell脚本实战12-Web及MySQL服务异常监控

1. 需求

用if条件语句针对Nginx Web服务或MySQL数据库服务是否正常进行检测,如果服务未启动,则启动相应的服务。

这是企业级运维实战的综合题目,需要编程者对Nginx Web服务和MySQL数据库服务很熟悉才行。这道示例同样适用于其它的Web服务和数据库服务。

2. 分析问题

监控Web服务和MySQL数据库服务是否异常的方法有哪些呢?见下表:

方式种类 具体方法
端口监控 1. 在服务器本地监控服务端口的常见命令有netstatsslsof
2. 从远端监控服务器本地端口的命令有telnetnmapnc
在客户端模拟用户访问 使用wgetcurl命令进行测试(如果检测数据库,则需要转为通过Web服务器去访问数据库),并对测试结果做三种判断:
1. 利用返回值(echo $?)进行判断
2. 获取特殊字符串进行判断(需要事先开发好程序)
3. 根据HTTP相应header的情况进行判断
登陆MySQL数据库判断 通过MySQL客户端连接数据库,根据返回值或返回内容判断。例如:mysql -uroot -p123456 -e "select version();" &>/dev/null; echo $?
监控服务进程或进程数 此方法适合本地服务器,注意,过滤的是进程的名字。命令如下:
1
ps -ef | grep nginx | wc -l`<br/>`ps -ef | grep mysql | wc -l

此外,对端口进程等进行判断时,尽量先通过grep过滤端口和进程特殊标记字符串,然后结合wc将过滤得到的结果转成行数再比较,这样相对简单有效。且经过wc -l命令处理之后的结果一定是数字,这样再进行判断就会比较简便。如果单纯地根据具体的列取具体的值判断会很麻烦吗如果确实想采用取值判断的方法,那就尽量用字符串比较的语法。

提示:掌握技术思想比解决问题本身更重要。

3. 监测MySQL数据库异常

3.1. MySQL数据库环境准备

准备如下:

1
2
3
4
# yum install -y mysql-server
# /etc/init.d/mysqld start
# netstat -lnpup | grep mysql
#<==只有MySQL服务正常启动后才可以继续做下面的实验

3.2. 通过命令行测试

通过命令行检测数据库服务是否正常,只有先确定命令行是正确的,才能确保将它放到脚本里也是正确的。

首先采用端口监控的方式。在服务器本地监控端口的命令有netstatsslsof,具体实现多种命令的方法如下:

  • netstat -lnp | grep 3306 | awk -F "[ :]+" '{print $5}'正常显示3306。这个就是前面所描述的根据具体的列取值判断的方法,获取到值,然后看啊可能其是否等于3306。但是不推荐采用这种取值方法,因为第一取值麻烦;第二如果使用数字比较,当端口不存在时就会报错。而一旦使用了取值判断方法,即使看起来是数字,也要尽量使用字符串进行比较,否则你将掉进坑里,很久都不会爬出来
  • netstat -lntup | grep 3306 | wc -l正常显示1。过滤关键字端口,转成数字,此方法很好。
  • netstat -lntup | grep mysql | wc -l正常显示1。过滤关键字进程吗,转成数字,此方法很好。
  • ss -lntup | grep mysql | wc -l正常显示1。ss类似于netstat命令,参数选项可通用
  • ss -lntup | grep 3306 | wc -l正常显示1
  • lsof -i tcp:3306 | wc -l 利用lsof检查tcp协议的3306端口。

从远端监控服务器监控本地端口的命令有telnetnmapnc,这三个命令有可能需要事先安装好才能使用,安装方法为:

1
# yum install -y telnet nmap nc

  • nmap 127.0.0.1 -p 3306 | grep open | wc -l 查看远端3306端口是否开通,过滤open关键字,结果返回1,说明有open关键字,表示3306端口是通的。
  • echo -e "\n" | telnet 127.0.0.1 3306 2> /dev/null | grep Connected | wc -l telnet是常用来检测远端服务器端口是通畅的一个好用的命令,在非交互时需要采用特殊写法才行,过滤的关键字为Connected,返回1,说明有Connected,表示3306端口是通的。
  • nc -w 2 127.0.0.1 3306 &> /dev/null nc的命令很强大,这里用来检测端口。根据执行命令的返回值判断端口是否通畅,如果返回0,则表示通畅,-w为超时时间。
  • 上面各个示例都是使用的127.0.0.1,在实际工作中,应该用自己服务器的IP来替代。

下面对服务进程数进行监控(适合本地服务器):

1
2
# ps -ef | grep mysql | grep -v grep | wc -l
3

以下是在客户端模拟用户访问的方式进行监控。

使用wget或curl命令访问URL地址来测试(如果要检测数据库是否异常,则先转为通过访问Web服务器去访问数据库)时,有以下几种判断思路:

  • 第一种,是根据执行命令的返回值判断成功与否,本例的URL使用了网上的地址,在实际工作中应该使用开发人员提供给我们的访问数据库的程序地址。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # wget --spider --timeout=10 --tries=2 www.baidu.com &> /dev/null
    #<== 在wget后面加url的检测方法。
    #<== &>/dev/null表示不输出,只看返回值。
    #<== --spider的意思是模拟爬取。
    #<== --timeout=10的意思是10秒超时。
    #<== --tries=2表示如果不成功,则重试2次。
    # echo $?
    0
    #<== 查看命令执行的返回值,0为成功。
    # curl -s -o /dev/null http://www.baidu,com
    #<== 利用curl进行检测
    #<== -s为沉默模式
    #<== -o /dev/null 表示输出定向到空
    # echo $?
    0
    #<== 查看命令执行的返回值,0为成功
  • 第二种,是根据执行命令后获取到的字符串进行判断。此方法需要有前端动态程序支持,即开发PHP或Java程序从数据库里面取出指定的字符串,看它和期待的是否相等。下面以PHP服务为例(对于一个PHP程序访问数据库,如果访问成功,则给出固定的输出)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # vim /server/scripts/testmysql.php
    <?php
    /*
    * This scripts is test the MySQL
    */
    //$link_id=mysql_connect('主机名','用户','密码');
    $link_id=mysql_connect('localhost','root','metianhai') or mysql_error();
    //$link_id=mysql_connect('localhost','test','');
    if($link_id){
    echo "mysql successful!";
    }else{
    echo mysql_error();
    }
    ?>
    • 命令行执行:

      1
      2
      3
      4
      # php /server/scripts/testmysql.php
      #<== 注意,.php需要执行(yum install -y php)安装
      mysql successful!
      #<==可以通过grep过滤上面输出的关键字,进而判断访问数据库是否成功
    • 提示:需要事先安装PHP软件才行,或者将程序放到LNMP服务器的站点目录,然后curl或wget访问http地址。

    • 此方法是监控数据库是否异常的最佳的方法。

3.3. 开发监控MySQL数据库的脚本

这里将给出多种开发脚本以供参考。

脚本1

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo method1-------------------
if [ `netstat -lnt | grep 3306 | awk -F "[ :]+" '{print $5}'` -eq 3306 ]
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

说明:

  • 这这个例子中的判断思路并不是很好
  • 最好不要用整数进行比较,因为一旦端口不存在,取值就会为空,进行整数比较会报错
  • 不要根据列取具体的值,而是要过滤关键字,通过wc转换成行数进行判断

脚本2

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo method2----------------
if [ "`netstat -lnt | grep 3306 | awk -F "[ :]+" '{print $5}'`" = "3306" ]
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

说明:

  • 在这里例子中,用字符串的方法及逆行比较就好多了,避免了脚本1中整数比较的错误发生,但是取值麻烦了一些。

脚本3

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo method3-----------------
if [ `netstat -lntup | grep mysqld | wc -l` -gt 0 ]
then
echo "MySQL is Running."
else
echo "MySQL is Stoppped."
/etc/init.d/mysqld start
fi

说明:

  • 过滤进程名,转成数字,很优秀的取值判断方法

脚本4

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo method4-----------------
if [ `lsof -i tcp:3306 | wc -l` -gt 0 ]
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

说明:

  • 过滤端口转成数字,很优秀的取值判断方法

脚本5

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
echo method5-------------------
[ `rpm -qa nmap | wc -l` -lt 1 ] && yum install nmap -y &> /dev/null
#<==防止因nmap没有安装而导致的错误
if [ `nmap 127.0.0.1 -p 3306 2> /dev/null | grep open | wc -l` -gt 0 ]
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

说明:

  • 远端的端口检查,推荐使用,统里,这里也不要过滤出open,然后再做字符比较,转成数字最佳

脚本6

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
echo method6-------------------
[ `rpm -qa nc | wc -l` -lt 1 ] && yum install -y nc &> /dev/null
#<==防止因nc没有安装而导致的错误
if [ `nc -w 2 127.0.0.1 3306 &> /dev/null && echo ok | grep ok | wc -l` -gt 0 ]
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

说明:

  • 这个例子中的判断有点特别,即若nc执行成功,则输出和之后的过滤都没有问题,最后转换成数字,思路决定出路。

脚本7

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo method7----------------
if [ `ps -ef | grep -v grep | grep mysql | wc -l` -gt 0 ] #<==过滤进程方式,排除自身
then
echo "MySQL is Running."
else
echo "MySQL is Stopped."
/etc/init.d/mysqld start
fi

4. 监控Nginx Web服务异常

监控Nginx Web服务异常的方法和监控MySQL数据库一样,也是使用端口、进程或者通过wget/curl访问来进行检测。

4.1. Nginx Web服务环境准备

环境准备如下:

1
2
3
4
5
6
7
8
# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
# yum insatll nginx -y
# /etc/init.d/nginx start
# echo theshu > /usr/share/nginx/html/index.html
#<==建立测试网页,内容为theshu
# curl http://127.0.0.1
theshu

4.2. 通过命令行检测Nginx服务是否正常

通过命令行检测Nginx服务是否正常,同样也只有在命令行下是正确的,才能确保它放到脚本里也是正确的。

首先采用端口监控的方式。在监控Nginx和监控数据库端口时,除了端口不同,其它的命令方法都是一模一样的。在服务器本地监控端口的命令有netstatsslsof,如下:

  • netstat -lnt | grep -w 80 | awk -F "[ :]+" '{print $5}'
  • netstat -lntup | grep -w 80 | wc -l
  • netstat -lntup | grep nginx | wc -l
  • ss -lntup | grep nginx | wc -l
  • ss -lntup | grep -w 80 | wc -l
  • lsof -i tcp:80 | wc -l

在远端监控服务器本地端口的命令有telnetnmapnc,如下:

  • nmap 127.0.0.1 -p 80 | grep open | wc -l
  • echo -e "\n" | telnet 127.0.0.1 80 2> /dev/null | grep Connected | wc -l
  • nc -w 2 127.0.0.1 80 &> /dev/null,然后echo $?

对服务进程或进程数进行监控的方式(适合本地服务器)如下:

  • ps -ef | grep nginx | grep -v grep | wc -l
  • ps -C nginx --no-header | wc -l

以下是在客户端模拟用户访问的监控方式。先通过wget或curl命令进行测试。执行wget或curl命令之后,再看返回值(echo $?)为0,则成功。

  • wget --spider --timeout=10 --tries=2 http://127.0.0.1 &> /dev/null然后echo $?
  • wget -T 10 -q --spider http://127.0.0.1 &> /dev/null然后echo $?
  • curl -s -o /dev/null http://127.0.0.1然后echo $?

以下是获取字符串的方式(判断获取的字符串是否和事先设定的相等)

1
2
# curl http://127.0.0.1
theshu

以下是根据HTTP响应的header的结果进行判断(200、301、302都表示正常)

1
2
# curl -I -s -w "%{http_code}\n" -o /dev/null http://127.0.0.1
200

4.3. 开发监控Nginx Web服务的脚本

在这里同样给出多个参考脚本。

脚本1

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method1--------------
if [ `netstat -lnt | grep 80 | awk -F "[ :]+" '{print $5}'` -eq 80 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本2

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method2--------------
if [ "`netstat -lnt | grep 80 | awk -F "[ :]+" '{print $5}'`" -eq "80" ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本3

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method3--------------
if [ `netstat -lntup | grep nginx | wc -l` -gt 0 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本4

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method4--------------
if [ `lsof -i tcp:80 | wc -l` -gt 0 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本5

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
echo http method5--------------
[ `rpm -qa nmap | wc -l` lt 1 ] && yum install -y nmap &> /dev/null
if [ `nmap 127.0.0.1 -p 80 2> /dev/null | grep open | wc -l` -gt 0 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本6

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
echo http method6--------------
[ `rpm -qa nc | wc -l` -lt 1 ] && yum install -y nc &> /dev/null
if [ `nc -w 2 127.0.0.1 80 &> /dev/null && echo ok | grep ok | wc -l` -gt 0 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本7

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method7--------------
if [ `ps -ef | grep -v grep | grep nginx | wc -l` -ge 1 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本8

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method8--------------
if [[ `curl -I -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1` =~ [23]0[012] ]]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本9

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method9--------------
if [ `curl -I http://127.0.0.1 2> /dev/null | head -1 | egrep "200|302|301" | wc -l` -eq 1 ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi

脚本10

1
2
3
4
5
6
7
8
9
#!/bin/bash
echo http method10--------------
if [ "`curl -s http://127.0.0.1`" = "theshu" ]
then
echo "Nginx is Running."
else
echo "Nginx is Stopped."
/etc/init.d/nginx start
fi
0%