简单备份监控程序

前言

随着维护服务器的增多,每天一台台检查备份已经不切实际,即使通过email的方式(备份脚本执行完后将备份信息发送到指定邮箱)检查也要耗费不少的时间,每天做这种重复性且繁杂的事情对我们这类懒人来说简直痛不欲生。经过一次惨痛的教训之后,决定做个备份检查(监控)程序。

原理

原理挺简单,本地服务器通过备份检查脚本检查备份文件是否存在,并将检查结果提交到sae的mysql数据库里,最后通过一个web页面将数据统一显示出来。

实例

假设有5台服务器(web1~web5),备份项目有:msyql数据库、mongodb数据库和/data/img的rsync+inotify实时同步,具体的备份信息如下:

备份项目 本地备份保存路径及文件名 异地备份保存路径及文件名
rsync+inotify /data/img /bk/$hostname/img/*
mysql /data/bk/msyql/mysql_日期.tgz /bk/$hostname/mysql/mysql_日期.tgz
mongodb /data/bk/mongodb/mongodb_日期.tgz /bk/$hostname/mongodb/mongodb_日期.tgz

程序文件说明:

文件名 功能
getdata.php 用于获取客户端POST过来的数据并将数据提交到mysql数据库
bk.sh 服务器上的备份检查脚本
bk.php web页面

首先到创建数据库:

1
2
3
4
5
6
7
8
9
CREATE TABLE `bk_monitor` (
`id` smailint NOT NULL auto_increment,
`hostname` varchar(20) default NULL,
`rsync` tinyint default NULL,
`mysql`varchar(20) default NULL,
`mongodb` varchar(20) default NULL,
`date` timestamp,
PRIMARY KEY (`id`)
)

getdata.php
用于获取客户端POST过来的数据并将数据提交到mysql数据库。
shell脚本中,只要使用curl -d xxx=xxx http://www.cszhi.com/getdata.php, 就可以将数据提交到服务器端的mysql数据库里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
< ?php
$posts=$_POST;
// 清除一些空白符号
foreach ($posts as $key => $value)
{
$posts[$key] = trim(addslashes($value));
}

//一些变量初始化
$db="bk_monitor";
$type=$posts['type'];

//0插入 & 1更新
switch ($type)
{
case 0:
$hostname=$posts['hostname'];
$rsync=$posts['rsync'];
$mysql=$posts['mysql'];
$mongodb=$posts['mongodb'];
$sql="insert into $db(hostname,rsync,mysql,mongodb) values('$hostname','$rsync','$mysql','$mongodb')";
break;
case 1:
$hostname=$posts['hostname'];
$rsync=$posts['rsync'];
$mysql=$posts['mysql'];
$mongo=$posts['mongo'];
$sql="update $db set rsync='$rsync',mysql='$mysql',mongodb='$mongodb' where hostname='$hostname'";
break;
default:
exit('error!!!');
}

//操作数据库
$conn = mysql_connect("localhost","root","aaabbb123","bk_monitor") or die("can't connect mysql:".mysql_error());
mysql_query($sql,$conn) or die("query error:".mysql_error().":".$sql);
mysql_close($conn);
?>

bk.sh
服务器上的备份检查脚本。脚本有验证异备服务器上的文件是否存在,所以需要先在服务器上设置能ssh无密码登陆到异备服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash
#Program:
#check the backup file and submit to the sae database
#History:
#2013/12/31 caishzh

#变量初始化
HOSTNAME=$(hostname)
TODAY=$(date +%Y%m%d)
REMOTEIP="10.35.14.55" #这里是异备服务器的ip地址
TIMESTAMP=$(date +%s)
TIMESTAMPFILE="/data/img/tmp/$TIMESTAMP"
[ -f "/data/img/tmp" ] || mkdir /data/img/tmp
LOG="/var/log/bk.log"
URL="http://webshot.sinaapp.com/getdata.php"
[ "$1" == 1 ] &amp;&amp; TYPE=0 || TYPE=1

#函数:检查本地备份文件和异地备份文件是否存在
function isExistFile()
{
[ -f $1/$2 ] || { echo 2;echo "$1/$2 doesn't exist..."&gt;&gt;$LOG;exit; }

#判断远程文件是否存在
if [ $(ssh -o ConnectTimeout=10 $REMOTEIP "test -f $3/$2 &amp;&amp; echo true || echo false") == "true" ];then
size=$(ssh -o ConnectTimeout=10 $REMOTEIP "ls -lh $3/$2|cut -d' ' -f5")
echo "0_$size"
else
{ echo 1;echo "remote file ${REMOTEIP}:$3/$2 doesn't exist...">>$LOG;exit; }
fi
}

echo "=====$(date +'%F %T') start=====" &gt;&gt;$LOG

#mysql和mongodb备份文件检查
MYSQBKFILE="$(isExistFile /data/bk/mysql mysql_${TODAY}.tgz /bk/${HOSTNAME}/mysql)"
MONGODBBKFILE="$(isExistFile /data/bk/mongodb mongodb_${TODAY}.tgz /bk/${HOSTNAME}/mysql)"

#rsync实时同步检查
#在同步目录的tmp目录下,touch一个文件(文件名就是当前时间戳),sleep 5秒后,再判断远程目录是否存在这个文件,存在则rsync同步正常,不存在则异常
#sleep的时间可以根据自己服务器的情况调整
touch $TIMESTAMPFILE
sleep 5
if [ $(ssh -o ConnectTimeout=10 $REMOTEIP "test -f /bk/${HOSTNAME}/img/tmp/${TIMESTAMP} &amp;&amp; echo true || echo false") != "true" ];then
RSYNCBAK=2
echo "rsync error..." >>$LOG
fi
RSYNCBAK=${RSYNCBAK:=0}

#将数据提交至数据库
curl --connect-timeout 10 -d type=${TYPE} -d rsync="${RSYNCBAK}" -d mysql="${MYSQBKFILE}" -d mongodb="${MONGODBBKFILE}" -d hostname="${HOSTNAME}" $URL

echo -e "=====$(date +'%F %T') finish=====\n" >>$LOG

第一次执行时,脚本后面加个参数1,往数据库里新插入一条数据:

1
sh /root/tool/bk.sh 1

将bk.sh放到crontab,每天早上8点定时运行:

1
echo "0 8 * * * root sh /root/tool/bk.sh" >>/etc/crontab

bk.php web页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=GB2312"/>
<title>bk monitor</title>
<link rel="stylesheet" href="style.css">
</link></head>
<body>
<h2>bk monitor</h2>
<table border='1'>
<tr>
<th>id</th>
<th>hostname</th>
<th>rsync</th>
<th>mysql</th>
<th>mongodb</th>
<th>date</th>
</tr>
< ?php
function status($bkname)
{
$str=explode("_",$bkname);
$status=(int)$str[0];
if ($status==0) {
if(empty($str[1]))
echo "<td>OK";
else
echo "<td>OK&nbsp;&nbsp;$str[1]</td>";
} elseif ($status==1) {
echo "<td>WARN</td>";
} elseif($bkname==2) {
echo "<td>ERROR</td>";
} else {
echo "<td>UNKNOW</td>";
}
}

//直接用sae提供的SaeMysql类操作mysql数据库
$mysql = new SaeMysql();
$sql = "SELECT * FROM bk_monitor";
$data = $mysql->getData( $sql );

//getDate返回的是二维数组,用foreach遍历下
foreach($data as $value)
{
echo "<tr>";
echo "<td>".$value['id']."</td>";
echo "<td>".$value['hostname']."</td>";
status($value['rsync']);
status($value['mysql']);
status($value['mongodb']);
echo "<td>".$value['date']."</td>";
echo "</tr>";
}
?>
</table>
</body>
</html>

界面如下:
1567499661114

如果想要显示的界面更加直观漂亮点,可以使用bootstrap做点样式,效果如下:
1567499675000