Shell脚本如何自动重启故障服务

wen 实用脚本 1

Shell脚本如何自动重启故障服务:从原理到实战的完整指南

目录导读

  1. 为什么需要自动重启故障服务?
  2. Shell脚本自动重启的核心原理
  3. 实战:编写一个高效的故障检测与重启脚本
  4. 常见问题与解决方案(Q&A)
  5. 优化与扩展:让脚本更稳定、更智能

为什么需要自动重启故障服务?

在生产环境中,服务可能因为内存泄漏、网络波动、并发过高或第三方依赖故障而意外崩溃,手动重启不仅响应慢,还可能因人为疏忽导致长时间宕机,Shell脚本自动重启机制能够:

Shell脚本如何自动重启故障服务

  • 缩短故障恢复时间:从分钟级降至秒级。
  • 减少人工干预:尤其适合凌晨或节假日无值守场景。
  • 记录故障日志:便于后续排查根本原因。

重要提示:自动重启是应急手段,不能替代代码层面的稳定性优化,建议同时搭配监控告警(如Prometheus + Alertmanager)做二级防护。


Shell脚本自动重启的核心原理

一个标准的自动重启脚本包含三个环节:

1 服务状态检测

常用方法包括:

  • 检查进程是否存在ps -ef | grep <服务名> | grep -v grep
  • 尝试端口连通性nc -zv <IP> <端口>curl -I http://localhost:端口
  • 检查进程返回值systemctl is-active <服务名>

2 故障判定逻辑

  • 若检测失败,立即执行重启命令。
  • 为防止“启动中误判”,可加入等待确认:重启后sleep 3-5秒,再检测一次。
  • 设置重启次数上限(如3次/小时),避免不停重启损坏系统资源。

3 重启与日志记录

  • 使用 systemctl restartservice restart
  • 将时间戳、检测结果、重启动作追加到 /var/log/auto-restart.log

实战:编写一个高效的故障检测与重启脚本

以下脚本综合了进程检测、端口检测、重启计数和日志记录,适用于多数Linux环境。

#!/bin/bash
# 自动检测并重启故障服务 - 版本1.0
# 适用系统:CentOS 7+/Ubuntu 18+/Debian 10+
SERVICE_NAME="your-service-name"     # 请替换为实际服务名
SERVICE_PORT=8080                    # 请替换为实际端口
LOG_FILE="/var/log/auto-restart-${SERVICE_NAME}.log"
MAX_RESTART_PER_HOUR=3
TEMP_FILE="/tmp/restart_count_${SERVICE_NAME}"
CURRENT_HOUR=$(date +%H)
# 记录日志函数
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> $LOG_FILE
}
# 检查服务进程是否存活
check_process() {
    if pgrep -x "$SERVICE_NAME" > /dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}
# 检查端口是否监听(需安装netcat)
check_port() {
    if nc -z -w2 localhost $SERVICE_PORT 2>/dev/null; then
        return 0
    else
        return 1
    fi
}
# 获取当前小时内的重启次数
get_restart_count() {
    if [ -f "$TEMP_FILE" ]; then
        LAST_HOUR=$(cat $TEMP_FILE | cut -d',' -f1)
        COUNT=$(cat $TEMP_FILE | cut -d',' -f2)
        if [ "$LAST_HOUR" != "$CURRENT_HOUR" ]; then
            echo 0
        else
            echo $COUNT
        fi
    else
        echo 0
    fi
}
# 主检测与重启逻辑
restart_service() {
    local count=$(get_restart_count)
    if [ "$count" -ge "$MAX_RESTART_PER_HOUR" ]; then
        log_message "WARNING: 已超过每小时最大重启次数 ($MAX_RESTART_PER_HOUR),跳过本次重启"
        exit 1
    fi
    log_message "检测到服务异常,尝试重启..."
    systemctl restart $SERVICE_NAME
    if [ $? -eq 0 ]; then
        sleep 3
        if check_process && check_port; then
            log_message "重启成功!服务已恢复"
            echo "$CURRENT_HOUR,$((count+1))" > $TEMP_FILE
        else
            log_message "重启后检测仍然失败,可能需要人工介入"
        fi
    else
        log_message "重启命令执行失败,请检查systemctl状态"
    fi
}
# --- 主循环 ---
if ! check_process && ! check_port; then
    log_message "服务异常:进程不存在或端口未监听"
    restart_service
fi

使用说明

  1. SERVICE_NAMESERVICE_PORT 替换为实际值。
  2. 添加执行权限:chmod +x /path/to/script.sh
  3. 添加到crontab每分钟执行:*/1 * * * * /path/to/script.sh

常见问题与解决方案(Q&A)

Q1:如何避免脚本在服务启动过程中误判为“故障”?

A:可在脚本开头检查 /var/lock/ 或创建一个临时标记文件,在系统服务启动完成后写入 /tmp/service_started.ok,脚本检测到该文件存在才执行故障判断,或者使用 systemctl is-active--wait 参数。

Q2:如果服务有多个进程,如何准确检测?

A:建议组合检测:

  • 使用 pgrep -f <完整程序名> 替代 -x(精确匹配)。
  • 或者检查最小进程数:if [ $(ps aux | grep -c <name>) -lt 2 ]

Q3:重启脚本挂掉了,怎么办?

A:使用 supervisordsystemd timer 来守护脚本本身,或者将脚本放入 /etc/cron.minutely,由cron兜底。

Q4:日志文件过大如何处理?

A:添加logrotate配置,或脚本内限制日志行数:

tail -n 1000 $LOG_FILE > $LOG_FILE.tmp && mv $LOG_FILE.tmp $LOG_FILE

Q5:如何发告警通知?

A:在 restart_service 函数内嵌入调用发送命令:

# 使用钉钉机器人
curl -X POST -H 'Content-Type: application/json' \
  -d '{"msgtype":"text","text":{"content":"服务重启通知"}}' \
  'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN'

(实际使用时请替换为真实域名,示例中为统一修改)


优化与扩展:让脚本更稳定、更智能

1 增加重试间隔

不要立即重启,可增加5秒冷却时间,防止循环重启消耗CPU。

2 区分“真实故障”与“临时抖动”

连续失败3次才认为真故障,可避免网络波动导致的不必要重启:

RETRY=0
while [ $RETRY -lt 3 ]; do
    sleep 2
    if check_process && check_port; then break; fi
    ((RETRY++))
done
if [ $RETRY -ge 3 ]; then restart_service; fi

3 支持多种服务管理器

兼容 systemctlservicedocker restart

restart_cmd() {
    if command -v systemctl &>/dev/null; then systemctl restart $1
    elif command -v service &>/dev/null; then service $1 restart
    elif command -v docker &>/dev/null; then docker restart $1
    else log_message "未找到合适的重启命令"; exit 1
    fi
}

4 集成到监控系统

将日志中“重启成功/失败”关键字通过 rsyslogfluentd 转发到集中日志平台,方便回溯。


通过Shell脚本自动重启故障服务,能显著提升系统可用性,关键在于:

  • 检测要准确(进程+端口双重验证)
  • 重启要克制(次数限制+等待确认)
  • 日志要完整(便于定位根因)

上述脚本已包含安全防护机制和实际可用的代码,可直接在生产环境验证,自动重启是治标,代码健壮性和资源限流才是治本,建议将本篇与故障根因分析流程结合使用,形成完整的SRE闭环。

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