本文目录导读:

我来详细介绍Shell脚本实现看门狗定时器的几种方法:
基础看门狗实现
简单的循环检测看门狗
#!/bin/bash
# 看门狗脚本
WATCHDOG_INTERVAL=10 # 检测间隔(秒)
WATCHDOG_TIMEOUT=30 # 超时时间(秒)
LAST_HEARTBEAT_FILE="/tmp/watchdog_last_heartbeat"
LOG_FILE="/var/log/watchdog.log"
# 创建或更新心跳时间戳
function send_heartbeat() {
echo "$(date +%s)" > "$LAST_HEARTBEAT_FILE"
echo "[$(date)] 心跳已发送" >> "$LOG_FILE"
}
# 检查是否超时
function check_timeout() {
if [ ! -f "$LAST_HEARTBEAT_FILE" ]; then
return 1 # 没有心跳文件,视为超时
fi
current_time=$(date +%s)
last_time=$(cat "$LAST_HEARTBEAT_FILE")
time_diff=$((current_time - last_time))
if [ $time_diff -gt $WATCHDOG_TIMEOUT ]; then
return 1 # 超时
fi
return 0 # 正常
}
# 看门狗主循环
function watchdog_main() {
echo "[$(date)] 看门狗服务启动" >> "$LOG_FILE"
echo "[$(date)] 检测间隔: ${WATCHDOG_INTERVAL}s, 超时时间: ${WATCHDOG_TIMEOUT}s" >> "$LOG_FILE"
while true; do
if ! check_timeout; then
echo "[$(date)] 警告: 检测到超时!执行恢复操作..." >> "$LOG_FILE"
# 执行恢复操作,比如重启服务
systemctl restart your_service 2>/dev/null || \
/etc/init.d/your_service restart 2>/dev/null
# 发送通知
send_alert_email "服务已超时,已自动重启"
fi
sleep $WATCHDOG_INTERVAL
done
}
# 发送警报邮件函数
function send_alert_email() {
local message="$1"
echo "看门狗警报: $message" | mail -s "[看门狗] 服务异常" admin@example.com
}
# 启动看门狗
watchdog_main
监控特定进程的看门狗
#!/bin/bash
# 进程监控看门狗
MONITOR_PROCESS="your_service_name" # 要监控的进程名
PROCESS_CHECK_INTERVAL=5 # 检测间隔
MAX_RESTART_ATTEMPTS=3 # 最大重启次数
RESTART_WINDOW=60 # 重启计数窗口(秒)
RESTART_COUNT=0
FIRST_RESTART_TIME=0
# 检查进程是否运行
function is_process_running() {
pgrep -x "$MONITOR_PROCESS" > /dev/null 2>&1
}
# 重启进程
function restart_process() {
echo "[$(date)] 正在重启进程: $MONITOR_PROCESS"
# 尝试优雅停止
pkill -SIGTERM "$MONITOR_PROCESS" 2>/dev/null
sleep 2
# 强制杀掉
pkill -SIGKILL "$MONITOR_PROCESS" 2>/dev/null
sleep 1
# 启动进程
systemctl start "$MONITOR_PROCESS" 2>/dev/null || \
/etc/init.d/"$MONITOR_PROCESS" start 2>/dev/null
return $?
}
# 重置重启计数
function reset_restart_count() {
current_time=$(date +%s)
if [ $((current_time - FIRST_RESTART_TIME)) -gt $RESTART_WINDOW ]; then
RESTART_COUNT=0
FIRST_RESTART_TIME=0
fi
}
# 主监控循环
while true; do
if ! is_process_running; then
reset_restart_count
if [ $RESTART_COUNT -lt $MAX_RESTART_ATTEMPTS ]; then
((RESTART_COUNT++))
if [ $RESTART_COUNT -eq 1 ]; then
FIRST_RESTART_TIME=$(date +%s)
fi
echo "[$(date)] 进程未运行,尝试重启 (第${RESTART_COUNT}次)"
if restart_process; then
echo "[$(date)] 重启成功"
else
echo "[$(date)] 重启失败"
fi
else
echo "[$(date)] 错误: 已达到最大重启次数"
# 发送紧急通知
send_alert_escalation "$MONITOR_PROCESS"
fi
fi
sleep $PROCESS_CHECK_INTERVAL
done
超时监控看门狗
#!/bin/bash
# 超时监控看门狗 - 监控某个命令的执行时间
TIMEOUT=60 # 超时时间(秒)
CMD_TO_MONITOR="your_long_running_command"
STATUS_FILE="/tmp/wdt_status"
# 监控命令执行
function monitor_command() {
local start_time=$(date +%s)
local timeout=$1
local cmd="$2"
# 在后台执行命令
eval "$cmd" &
local cmd_pid=$!
# 等待命令完成或超时
while kill -0 $cmd_pid 2>/dev/null; do
current_time=$(date +%s)
elapsed=$((current_time - start_time))
if [ $elapsed -gt $timeout ]; then
echo "[$(date)] 命令执行超时,强制终止 PID: $cmd_pid"
kill -9 $cmd_pid 2>/dev/null
return 1
fi
sleep 1
done
wait $cmd_pid
return $?
}
# 示例:监控数据库查询
function monitor_db_query() {
local query="SELECT COUNT(*) FROM large_table;"
local timeout=30
echo "[$(date)] 开始监控数据库查询"
if ! monitor_command $timeout "mysql -e \"$query\""; then
echo "[$(date)] 数据库查询超时,记录日志"
# 记录到系统日志
logger -t watchdog "数据库查询超时"
fi
}
# 监控Web服务响应
function monitor_web_service() {
local url="http://localhost:8080/health"
local timeout=10
echo "[$(date)] 检查Web服务: $url"
if ! monitor_command $timeout "curl -s -o /dev/null -w '%{http_code}' $url"; then
echo "[$(date)] Web服务响应超时"
# 重启Web服务器
systemctl restart nginx 2>/dev/null
fi
}
# 主循环
while true; do
monitor_db_query
monitor_web_service
# 记录状态
echo "OK $(date +%s)" > "$STATUS_FILE"
sleep 30
done
使用定时任务的看门狗
#!/bin/bash
# 通过cron运行的看门狗检查脚本
# 将此脚本添加到crontab:*/5 * * * * /path/to/watchdog_cron.sh
CONFIG_FILE="/etc/watchdog.conf"
STATUS_FILE="/tmp/watchdog_status"
LOG_FILE="/var/log/watchdog.log"
# 发送心跳
function heartbeat() {
touch "$STATUS_FILE"
echo "$(date +%s)" > "$STATUS_FILE"
}
# 检查服务状态
function check_services() {
local services=("nginx" "mysql" "redis")
local failed_services=()
for service in "${services[@]}"; do
if ! systemctl is-active --quiet "$service" 2>/dev/null; then
failed_services+=("$service")
fi
done
if [ ${#failed_services[@]} -gt 0 ]; then
echo "[$(date)] 检测到服务异常: ${failed_services[*]}" >> "$LOG_FILE"
for service in "${failed_services[@]}"; do
systemctl restart "$service" 2>/dev/null
echo "[$(date)] 重启服务: $service" >> "$LOG_FILE"
fi
fi
}
# 检查系统资源
function check_system_resources() {
# CPU负载
load=$(uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | tr -d ' ')
if (( $(echo "$load > 10" | bc -l) )); then
echo "[$(date)] CPU负载过高: $load" >> "$LOG_FILE"
# 执行清理或警报
fi
# 内存使用
memory_usage=$(free | grep Mem | awk '{print $3/$2 * 100.0}')
if (( $(echo "$memory_usage > 90" | bc -l) )); then
echo "[$(date)] 内存使用过高: ${memory_usage}%" >> "$LOG_FILE"
fi
# 磁盘使用
disk_usage=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$disk_usage" -gt 90 ]; then
echo "[$(date)] 磁盘使用过高: ${disk_usage}%" >> "$LOG_FILE"
# 清理日志或警报
fi
}
# 主函数
function main() {
heartbeat
check_services
check_system_resources
}
main
完整的看门狗系统
#!/bin/bash
# 完整的看门狗系统脚本
# 使用方法: ./watchdog.sh {start|stop|status|heartbeat}
# 配置
APP_NAME="myapp"
PID_FILE="/var/run/${APP_NAME}_watchdog.pid"
LOG_FILE="/var/log/${APP_NAME}_watchdog.log"
STATUS_FILE="/tmp/${APP_NAME}_status"
HEARTBEAT_INTERVAL=10
TIMEOUT=30
MAX_RESTARTS=3
RESTART_WINDOW=300
# 初始化变量
RESTART_COUNT=0
FIRST_RESTART=0
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# 发送心跳
heartbeat() {
echo "ALIVE" > "$STATUS_FILE"
date +%s >> "$STATUS_FILE"
}
# 检查状态
check_status() {
if [ -f "$STATUS_FILE" ]; then
local timestamp=$(tail -1 "$STATUS_FILE" 2>/dev/null)
local current_time=$(date +%s)
if [ -n "$timestamp" ] && [ "$timestamp" -gt 0 ]; then
local elapsed=$((current_time - timestamp))
if [ "$elapsed" -le "$TIMEOUT" ]; then
return 0 # 正常
fi
fi
fi
return 1 # 超时
}
# 重启应用
restart_app() {
log "正在重启应用..."
# 停止应用
systemctl stop "$APP_NAME" 2>/dev/null
sleep 2
# 确保进程已停止
local pid=$(pgrep -x "$APP_NAME" 2>/dev/null)
if [ -n "$pid" ]; then
kill -9 "$pid" 2>/dev/null
sleep 1
fi
# 启动应用
systemctl start "$APP_NAME" 2>/dev/null
if [ $? -eq 0 ]; then
log "应用重启成功"
return 0
else
log "应用重启失败"
return 1
fi
}
# 启动看门狗
start_watchdog() {
if [ -f "$PID_FILE" ]; then
local old_pid=$(cat "$PID_FILE")
if kill -0 "$old_pid" 2>/dev/null; then
log "看门狗已在运行 (PID: $old_pid)"
exit 1
fi
fi
log "启动看门狗..."
# 启动看门狗主循环
(
log "看门狗已启动 (PID: $$)"
echo $$ > "$PID_FILE"
while true; do
if ! check_status; then
log "检测到超时!"
# 检查重启次数
local current_time=$(date +%s)
if [ $RESTART_COUNT -eq 0 ]; then
FIRST_RESTART=$current_time
fi
if [ $((current_time - FIRST_RESTART)) -gt $RESTART_WINDOW ]; then
RESTART_COUNT=0
fi
if [ $RESTART_COUNT -lt $MAX_RESTARTS ]; then
((RESTART_COUNT++))
restart_app
else
log "达到最大重启次数,等待人为干预"
# 发送警报
echo "应用 $APP_NAME 出现问题,请检查" | \
mail -s "[紧急] 应用异常" admin@example.com
fi
fi
sleep $HEARTBEAT_INTERVAL
done
) &
log "看门狗已启动"
}
# 停止看门狗
stop_watchdog() {
if [ -f "$PID_FILE" ]; then
local pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
log "看门狗已停止"
fi
rm -f "$PID_FILE"
fi
}
# 查看状态
status_watchdog() {
if [ -f "$PID_FILE" ]; then
local pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
echo "看门狗正在运行 (PID: $pid)"
if check_status; then
echo "应用状态: 正常"
else
echo "应用状态: 异常(超时)"
fi
else
echo "看门狗未运行(PID文件存在但进程不存在)"
rm -f "$PID_FILE"
fi
else
echo "看门狗未运行"
fi
}
# 主函数
case "${1:-help}" in
start)
start_watchdog
;;
stop)
stop_watchdog
;;
restart)
stop_watchdog
sleep 1
start_watchdog
;;
status)
status_watchdog
;;
heartbeat)
heartbeat
echo "心跳已发送"
;;
help|*)
echo "用法: $0 {start|stop|restart|status|heartbeat}"
echo ""
echo "Commands:"
echo " start 启动看门狗"
echo " stop 停止看门狗"
echo " restart 重启看门狗"
echo " status 查看看门狗状态"
echo " heartbeat 发送心跳信号"
exit 1
;;
esac
exit 0
应用端使用示例
#!/bin/bash
# 应用主程序
WATCHDOG_SCRIPT="/path/to/watchdog.sh"
HEARTBEAT_INTERVAL=5
# 发送心跳信号
function send_heartbeat() {
$WATCHDOG_SCRIPT heartbeat
}
# 主程序循环
function main() {
echo "应用启动..."
# 主业务逻辑
while true; do
# 执行实际工作
do_work
# 发送心跳
send_heartbeat
# 等待
sleep $HEARTBEAT_INTERVAL
done
}
main
使用方法
-
启动看门狗:
./watchdog.sh start
-
停止看门狗:
./watchdog.sh stop
-
查看状态:
./watchdog.sh status
-
发送心跳(应用调用):
./watchdog.sh heartbeat
这些脚本可以根据实际需求进行调整和扩展,选择合适的看门狗实现方式取决于你的具体应用场景和需求。