背景

我有很多台主机,公网、内网的都有,形式各异。有的时候,因为他人误操作、停电、被攻击,或者系统崩溃等事故,会导致主机无法正常运转。往常,我并不能在第一时间得知消息并及时采取措施。所以,我希望能够有一套系统来监控我的主机是否正常。

市面上已经有这样的系统,但是我想了想觉得要实现我的需求并不是很困难,所以就决定自己做一套这样的系统。

需求分析

在指定被监控的主机(slave)无法向云监控服务器(master)发送请求时,使用短信通知用户处理。

基本原理

  • slave每隔1分钟向master发送指定格式请求,参数包括nametokenname用于表明自己的身份(主机名),且只当token正确时,master才接受请求。
  • master在接收到请求后,会将数据文件data.jsonname键所对应的值赋为当前的timestamp(如果name键不存在则新建一个)。
  • master上每隔1分钟检查一次data.json中每一个name的键值,并比较当前timestamp与各键值的差值。当某name差值大于300(超过5分钟未更新)则调用短信发送的API,提醒用户该主机出现问题。

代码示例

master中接收请求并修改数据文件的php脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$name = $_GET["name"];
$token = $_GET["token"];

if ($name=="" || $token!="example_token")
{
echo "Error";
exit(1);
}

$value = file_get_contents("data.json");
$data = json_decode($value,true);

$data[$name]=time();

file_put_contents("data.json",json_encode($data));

echo "Get";

master中检查数据文件并发送短信的python脚本

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
59
60
#! /usr/bin/python3

# 每分钟运行一次,可在crontab中配置

import json
import time
from qcloudsms_py import SmsSingleSender
from qcloudsms_py.httpclient import HTTPError
import datetime

# 腾讯云发短信的脚本,具体规则可参阅官方网站
def sendSMS(id):
appid = 1400000000
appkey = "exampleappkey"
phone_numbers = ["18000000000"]
template_id = 190000
sms_sign = "vvzero"

ssender = SmsSingleSender(appid, appkey)
params = [id]

try:
result = ssender.send_with_param(86, phone_numbers[0],
template_id, params, sign=sms_sign, extend="", ext="")
except HTTPError as e:
logFile.write(str(e)+"\n")
except Exception as e:
logFile.write(str(e)+"\n")

logFile.write(str(result)+"\n")



logFile = open("hostsMonitor.log",'a')
logFile.write("\n"+str(datetime.datetime.now())+"\n")

try:
inputFile = open("/var/www/iot/checkAlive/data.json",'r')
except Exception as e:
logFile.write(str(e)+"\n")

try:
data = json.load(inputFile)
except Exception as e:
logFile.write(str(e)+"\n")

try:
inputFile.close()
except Exception as e:
logFile.write(str(e)+"\n")

for host in data:
if (int(time.time()) - int(data[host]) >= 300) and (int(time.time()) - int(data[host]) <= 360): # 超过5分钟没有心跳包就发短信
try:
sendSMS(host)
logFile.write("Problem found in "+host+". SMS has been sent.\n")
except Exception as e:
logFile.write(str(e)+"\n")

logFile.close()

slave中的crontab配置,其他定时任务同理

1
*/1 * * * * curl -X GET 'https://monitor.example.com/?name=hostname&token=example_token'

实际效果

这几天将这套系统运行了一下,没有什么问题。并且在我路由器掉线的时候及时提醒了我。