使用 Supervisor 监控 Java 进程并在进程关闭时自动调用 Shell 脚本重启

276 阅读3分钟

使用 Supervisor 监控 Java 进程并在进程关闭时自动调用 Shell 脚本重启,是一种可靠的方案。以下是详细配置步骤:


1. 安装 Supervisor

如果尚未安装,在 Linux 系统上执行:

sudo apt update && sudo apt install supervisor -y  # Debian/Ubuntu
sudo yum install supervisor -y                     # CentOS/RHEL

安装后启动并设置开机自启:

sudo systemctl enable supervisor
sudo systemctl start supervisor

2. 编写 Shell 脚本(用于监控 Java 进程)

创建脚本(如 /opt/scripts/monitor_supervisor_zsba_java.sh):

#!/bin/bash

# 配置项
JAVA_PROCESS_NAME="bidding-zsbayy/jar/one-main-0.0.1-SNAPSHOT.jar"
LOG_FILE="/var/log/bidding_supervisor_zsbayy_java_monitor.log"
RESTART_SCRIPT="/home/bid/bidding-zsbayy/one.sh"
APP_PORT=9691                     # 您的Java应用端口
MAX_START_TIME=180                # 3分钟启动超时(单位:秒)
HEALTH_CHECK_INTERVAL=30          # 健康检查间隔(秒)

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 健康检查(通过端口检测)
is_fully_started() {
    if netstat -tlnp | grep -w "$APP_PORT" | grep -q java; then
        return 0
    fi
    return 1
}

# 主监控循环
log "启动监控守护进程(最大启动等待时间:${MAX_START_TIME}秒)..."
while true; do
    if ! pgrep -f "$JAVA_PROCESS_NAME" > /dev/null; then
        log "检测到Java进程停止,开始重启..."
        start_time=$(date +%s)
        
        # 异步启动Java进程
        "$RESTART_SCRIPT" start >> "$LOG_FILE" 2>&1 &
        
        # 等待启动完成
        while [ $(($(date +%s) - start_time)) -lt $MAX_START_TIME ]; do
            if is_fully_started; then
                log "Java进程启动成功(耗时 $(( $(date +%s) - start_time )) 秒)"
                break
            fi
            sleep 5
        done

        # 超时处理
        if ! is_fully_started; then
            log "警告:Java进程启动超时(超过 ${MAX_START_TIME} 秒)"
            pkill -f "$JAVA_PROCESS_NAME"
        fi
    else
        # 进程存在时的健康检查
        if ! is_fully_started; then
            log "检测到异常状态(进程存在但端口未监听),尝试恢复..."
            pkill -f "$JAVA_PROCESS_NAME"
        fi
    fi
    
    sleep $HEALTH_CHECK_INTERVAL
done

赋予执行权限:

sudo chmod +x /opt/scripts/monitor_supervisor_zsba_java.sh

3. 配置 Supervisor 监控

创建配置文件(如 /etc/supervisor/conf.d/java_app.conf):

[program:java_app]
command=/opt/scripts/monitor_supervisor_zsba_java.sh  # 指定你的脚本路径
autostart=true                           # 随 Supervisor 启动
autorestart=true                         # 自动重启(脚本退出时)
startsecs=300                             # 启动等待时间(秒)
startretries=3                           # 启动失败重试次数
stderr_logfile=/var/log/java_app_err.log # 错误日志
stdout_logfile=/var/log/java_app_out.log # 输出日志
user=your_user                          # 运行用户(建议非 root)
environment=JAVA_HOME="/usr/java/jdk17"  # 可选:指定 Java 环境

4. 应用配置并启动

sudo supervisorctl reread                  # 重新加载配置
sudo supervisorctl update                  # 更新任务
sudo supervisorctl start java_app          # 启动监控

可能的错误:

root@localhost:/etc/supervisor/conf.d# tail -f /var/log/supervisor/supervisord.log 2025-05-09 10:30:40,748 INFO gave up: java_zsbbyy_admin_app entered FATAL state, 
too many start retries too quickly 2025-05-09 10:33:45,034 INFO spawned: 
'java_zsbbyy_admin_app' with pid 140577

查看 supervisord.log 获取详细错误:

sudo tail -f /var/log/supervisor/supervisord.log

monitor_supervisor_zsba_java.sh 配置的状态直接退出了!


5. 验证 Supervisor 状态

sudo supervisorctl status java_app         # 查看Supervisor进程状态
tail -f /var/log/java_app_out.log          # Supervisor监控日志

6. 检查监控脚本产生的日志

tail -f /var/log/bidding_supervisor_zsbayy_java_monitor.log # 查看监控脚本产生的日志

image.png


关键点说明

  1. 进程匹配逻辑

    • 脚本中的 ps -ef | grep 需确保能唯一匹配到你的 Java 进程(避免误判)。
    • 更精准的方式:使用 pgrep -f "your-java-app.jar"
  2. Supervisor 重启机制

    • 若脚本执行后退出(即使 Java 进程启动成功),Supervisor 会因 autorestart=true 重复触发脚本。
    • 解决方案:脚本末尾添加 sleep 1 或让脚本常驻(如 tail -f /dev/null)。
  3. 资源限制(可选)
    在 Supervisor 配置中添加:

    stopsignal=TERM                        # 停止信号
    stopwaitsecs=30                        # 等待停止超时
    priority=100                           # 优先级
    

替代方案对比

方案优点缺点
Supervisor轻量、配置简单需手动处理进程匹配
systemd原生支持、功能强大学习曲线较陡
cron + 脚本无需额外工具监控延迟(分钟级)

常见问题

  • 问题1:Supervisor 报错 BACKOFF (Exited too quickly)
    解决:检查脚本是否有执行权限,或添加 sleep 防止立即退出。

  • 问题2:Java 进程启动但 Supervisor 仍重启
    解决:确保脚本持续运行(如末尾加 while true; do sleep 60; done)。

按此配置后,Supervisor 会持续监控 Java 进程状态,异常时自动调用脚本恢复服务。