如何编写应用程序崩溃重启脚本

wen 实用脚本 2

从原理到实战的完整指南

如何编写应用程序崩溃重启脚本

目录导读

  1. 理解崩溃重启脚本的核心价值 – 为什么需要自动化恢复机制
  2. 崩溃检测原理与常见策略 – 如何准确判断应用是否“真死”
  3. 脚本编写语言选择与对比 – Bash、Python、PowerShell 优劣分析
  4. 实战:Linux下Bash重启脚本示例 – 带日志、限频、健康检查
  5. 实战:Windows下PowerShell监控脚本 – 服务自动拉起方案
  6. 高级技巧:防止重启风暴与优雅退出 – 使用锁文件与守护进程模式
  7. 常见问题问答 – 覆盖真实运维场景

理解崩溃重启脚本的核心价值

在线上环境,应用程序因内存泄漏、第三方依赖超时或异常数据导致崩溃,是运维中最常见的事故之一,手动重启不仅响应慢,且在凌晨或节假日会严重拖累可用性指标,一个健壮的重启脚本至少能实现:

  • 自动检测:每秒或每几秒检查进程是否存活
  • 自动拉起:检测到崩溃后立即执行启动命令
  • 失败降级:如果连续多次重启失败,自动停止并发送告警

根据 Google SRE 书中的经验,超过80%的进程级故障可通过简单的“重启”策略在30秒内恢复。编写崩溃重启脚本是所有运维、后端开发人员的必备技能


崩溃检测原理与常见策略

检测“崩溃”不能只依赖进程是否存在,因为可能出现“僵尸进程”或应用虽在运行但无响应,常见检测手段包括:

策略 原理 适用场景
PID 文件检查 检查 /var/run/app.pid 对应的进程是否存在 简单服务
系统服务状态 systemctl is-activesc query 托管服务
健康HTTP端点 http://localhost:8080/health 发起请求 Web 应用
端口监听检测 netstat -tlnp | grep :8080 网络服务

最佳实践:先通过 PID 快速判断进程是否消失;如果进程还在但无响应,再使用超时的 HTTP 健康检查作为兜底。


脚本编写语言选择与对比

  • Bash:Linux 环境首选,轻量无依赖,适合简单重启逻辑,缺点是不擅长时间处理与 HTTP 请求。
  • Python:跨平台,有 requestspsutil 库,可轻松实现健康检查与复杂失败策略。
  • PowerShell:Windows 原生,对 Windows 服务(如 IIS、Windows Service)支持极好。
  • Node.js:适合与 Node 应用共享环境,但需要额外安装运行时。

对于大多数场景,Linux 推荐 Bash + curl,Windows 推荐 PowerShell,如果需要在两个平台共用一套逻辑,优先选择 Python。


实战:Linux下Bash重启脚本示例

以下脚本实现:进程不存在时重启,同时记录日志、限制重启频率,并对健康端点进行检查。

#!/bin/bash
APP_NAME="myapp"
APP_PORT=8080
HEALTH_URL="http://localhost:8080/health"
LOG_FILE="/var/log/app_restart.log"
LOCK_FILE="/tmp/app_restart.lock"
MAX_RETRIES=3
RETRY_INTERVAL=60
# 防并发锁
if [ -f "$LOCK_FILE" ]; then
    echo "$(date) - 已有重启脚本在运行,退出" >> $LOG_FILE
    exit 1
fi
trap 'rm -f $LOCK_FILE; exit' INT TERM EXIT
echo $$ > $LOCK_FILE
# 检查进程是否存活
pid=$(pgrep -f "$APP_NAME")
if [ -z "$pid" ]; then
    echo "$(date) - 进程不存在,开始重启" >> $LOG_FILE
    # 启动应用(根据实际情况替换启动命令)
    /usr/local/bin/start_myapp.sh
    # 等待启动完成
    sleep 10
    # 健康检查
    if curl -sfI --connect-timeout 5 "$HEALTH_URL" > /dev/null; then
        echo "$(date) - 重启成功" >> $LOG_FILE
    else
        echo "$(date) - 健康检查失败" >> $LOG_FILE
    fi
fi
rm -f $LOCK_FILE

将此脚本放入 crontab,每分钟执行一次:

* * * * * /opt/scripts/restart_monitor.sh

实战:Windows下PowerShell监控脚本

针对 Windows 服务,以下脚本检测服务状态并自动启动:

$serviceName = "MyAppService"
$logPath = "C:\Logs\restart.log"
$maxAttempts = 3
$attempt = 0
while ($attempt -lt $maxAttempts) {
    $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
    if ($service.Status -ne "Running") {
        Add-Content -Path $logPath -Value "$(Get-Date) - 服务 $serviceName 已停止,尝试启动"
        Start-Service -Name $serviceName
        Start-Sleep -Seconds 10
        $service = Get-Service -Name $serviceName
        if ($service.Status -eq "Running") {
            Add-Content -Path $logPath -Value "$(Get-Date) - 启动成功"
            break
        } else {
            $attempt++
            Add-Content -Path $logPath -Value "$(Get-Date) - 第 $attempt 次启动失败"
            Start-Sleep -Seconds 30
        }
    } else {
        Add-Content -Path $logPath -Value "$(Get-Date) - 服务正常运行"
        break
    }
}
if ($attempt -ge $maxAttempts) {
    Add-Content -Path $logPath -Value "$(Get-Date) - 达到最大重试次数,发送告警"
    # 发送邮件或执行其他告警操作
}

可通过 Windows 任务计划程序设置为每分钟运行一次。


高级技巧:防止重启风暴与优雅退出

重启风暴指应用在短时间内反复崩溃与重启,导致日志激增、CPU飙升甚至服务器负载过高,解决方案:

  1. 时间窗口限频:记录每次重启时间,1小时内重启超过3次则暂停重启,改为告警。
  2. 锁文件与PID文件双重检查:防止同时启动多个实例。
  3. 启动前清理临时文件:避免重启后因旧数据二次崩溃。
  4. 优雅退出:使用 kill -15 发送SIGTERM信号,给应用5秒清理资源,再使用 kill -9

示例:Bash 中实现优雅退出函数:

graceful_shutdown() {
    pid=$1
    timeout=5
    kill $pid 2>/dev/null
    while [ $timeout -gt 0 ] && kill -0 $pid 2>/dev/null; do
        sleep 1
        let timeout--
    done
    kill -9 $pid 2>/dev/null
}

常见问题问答

Q1:脚本检测不到应用进程,但应用明明在运行? A:通常因为进程名不精确,建议使用 pgrep -f 匹配完整命令行参数,或使用固定 PID 文件,如果是Java应用,进程名是 java,需要用 ps aux | grep your.jar 来过滤。

Q2:重启脚本自己崩溃了怎么办? A:推荐使用系统级监控工具(如 monit、supervisord)或系统服务(systemd 的 Restart=always 策略)来管理脚本自身,简单情况下,crontab 天然具备周期重检特性。

Q3:健康检查返回200但应用实际报错? A:这是典型的“假健康”问题,建议健康端点不仅返回200,还应检查数据库连接、缓存服务等核心依赖是否正常,并在返回体中包含状态字段(如 {"status":"ok"}),脚本解析该字段再判断。

Q4:如何将重启日志发送到集中监控? A:可以将日志写入标准输出,然后使用 rsyslog 转发到日志服务器,或脚本中直接调用 API 发送到 datadog、zabbix 等平台,也可以直接使用 logger 命令写入系统日志。

Q5:Windows 脚本如何支持多实例应用? A:可以在服务名中加入实例编号(如 MyAppService_1, MyAppService_2),脚中循环检测每个实例,或者通过按端口号查找进程,如 Get-NetTCPConnection -LocalPort 8080


编写崩溃重启脚本的核心在于“准确检测 + 限制频率 + 日志记录 + 降级告警”,建议优先使用操作系统自带工具(systemd、supervisord、Windows Service Recovery)完成基础监控,脚本作为补充方案处理复杂业务健康检查,在生产上线前,务必在测试环境模拟多次崩溃场景,验证脚本不会导致重启风暴。

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