生產環境中 Java 應用(如 Tomcat)偶發記憶體洩漏、死鎖或 OOM 導致進程掛掉。需要一個輕量級的 Shell 腳本,定期檢測進程狀態,自動重啟並記錄日誌,作為監控系統的補充而非替代。
#!/bin/bash
# ==========================================
# Tomcat 進程監控自動重啟腳本
# 作者:系統運維團隊
# 版本:v1.2
# 依賴:ps, grep, awk, kill, sleep
# ==========================================
set -euo pipefail
# ========= 設定區 =========
APP_NAME="tomcat"
APP_HOME="/opt/tomcat"
START_SCRIPT="$APP_HOME/bin/startup.sh"
SHUTDOWN_SCRIPT="$APP_HOME/bin/shutdown.sh"
PID_FILE="$APP_HOME/tomcat.pid"
LOG_FILE="/var/log/tomcat_monitor.log"
CHECK_INTERVAL=30
MAX_RESTART_ATTEMPTS=3
# ============================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
get_pid() {
# 精確匹配 java 進程中的 catalina.base
pgrep -f "catalina.base=$APP_HOME" | head -1
}
cleanup_work_dir() {
log "清理工作目錄: $APP_HOME/work/*"
rm -rf "$APP_HOME"/work/* 2>/dev/null
rm -rf "$APP_HOME"/temp/* 2>/dev/null
}
start_app() {
log "啟動 $APP_NAME ..."
if [[ -f "$START_SCRIPT" ]]; then
cd "$APP_HOME"
nohup "$START_SCRIPT" >> "$APP_HOME/logs/catalina.out" 2>&1 &
sleep 3
else
log "錯誤:找不到啟動腳本 $START_SCRIPT"
return 1
fi
}
stop_app() {
local pid=$1
log "嘗試優雅關閉 PID: $pid"
if [[ -f "$SHUTDOWN_SCRIPT" ]]; then
"$SHUTDOWN_SCRIPT" 2>/dev/null
sleep 5
fi
# 檢查是否還在運行
if kill -0 "$pid" 2>/dev/null; then
log "優雅關閉失敗,強制終止 PID: $pid"
kill -9 "$pid"
sleep 2
fi
}
# ========= 主邏輯 =========
log "=== Tomcat 監控啟動 ==="
restart_count=0
last_restart_time=0
while true; do
PID=$(get_pid)
if [[ -z "$PID" ]]; then
log "偵測到 $APP_NAME 進程不存在"
# 防止頻繁重啟(30分鐘內最多3次)
current_time=$(date +%s)
if (( current_time - last_restart_time > 1800 )); then
restart_count=0
fi
if (( restart_count < MAX_RESTART_ATTEMPTS )); then
cleanup_work_dir
start_app
((restart_count++))
last_restart_time=$current_time
log "重啟嘗試 $restart_count/$MAX_RESTART_ATTEMPTS"
else
log "錯誤:短時間內重啟次數過多,停止嘗試,請人工介入"
# 可在此加入告警發送:郵件、釘釘、企業微信等
fi
else
# 進程存在,重置計數器
if (( restart_count > 0 )); then
log "$APP_NAME 運行正常,重置重啟計數器"
restart_count=0
fi
fi
sleep "$CHECK_INTERVAL"
done
| 技術點 | 說明 |
|---|---|
pgrep -f "catalina.base=..." | 精確匹配 Tomcat 進程,避免誤殺其他 Java 進程 |
set -euo pipefail | 嚴格模式:變量未定義報錯、命令失敗即退出、管道失敗傳遞 |
nohup ... & | 後台運行且免疫 SIGHUP,配合輸出重導向 |
| 優雅關閉 → 強制殺掉 | 先嘗試 shutdown.sh 釋放資源,失敗再 kill -9 |
| 工作目錄清理 | 清除 work/temp 目錄防止 JSP 編譯殘留導致啟動異常 |
| 頻率限制 | 30分鐘內最多3次重啟,防止故障風暴 |
sudo tee /usr/local/bin/tomcat_monitor.sh > /dev/null <<'EOF'
# 腳本內容...
EOF
sudo chmod +x /usr/local/bin/tomcat_monitor.sh
sudo tee /etc/systemd/system/tomcat-monitor.service > /dev/null <<'EOF'
[Unit]
Description=Tomcat Process Monitor
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/tomcat_monitor.sh
Restart=always
RestartSec=10
User=tomcat
Group=tomcat
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now tomcat-monitor
nohup /usr/local/bin/tomcat_monitor.sh > /dev/null 2>&1 &
curl -f https://localhost:8080/health 而非僅檢查進程存活flock 防止多實例並發運行這個 Shell 腳本雖簡單,但涵蓋了進程檢測、優雅重啟、資源清理、頻率限制、日誌記錄等生產級要素。實際部署時建議配合 Systemd 管理,並根據業務特性加入 HTTP 健康檢查與告警通知,構建完整的自愈體系。