Shell脚本如何实现看门狗定时器

wen 实用脚本 15

本文目录导读:

Shell脚本如何实现看门狗定时器

  1. 基础看门狗实现
  2. 监控特定进程的看门狗
  3. 超时监控看门狗
  4. 使用定时任务的看门狗
  5. 完整的看门狗系统
  6. 应用端使用示例
  7. 使用方法

我来详细介绍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

使用方法

  1. 启动看门狗

    ./watchdog.sh start
  2. 停止看门狗

    ./watchdog.sh stop
  3. 查看状态

    ./watchdog.sh status
  4. 发送心跳(应用调用):

    ./watchdog.sh heartbeat

这些脚本可以根据实际需求进行调整和扩展,选择合适的看门狗实现方式取决于你的具体应用场景和需求。

抱歉,评论功能暂时关闭!