生產環境中 PHP-FPM 偶爾會因記憶體洩漏、死鎖、上游服務超時等原因導致停止響應 (502 Bad Gateway)。需一個輕量級監控腳本,定期檢查服務健康狀態,異常時自動重啟並記錄日誌。
curl 發送 HTTP HEAD 請求至指定監控頁面。200 OK。cron 定時執行 (建議每 1 分鐘)。為減輕負載,建立專用輕量頁面 /var/www/html/health.php:
<?php
// 僅回傳 200 與簡短內容,不連接資料庫、不載入框架
header('Content-Type: text/plain');
echo "OK";
?>
Nginx/Apache 配置允許存取此頁面。
#!/bin/bash
# PHP-FPM 健康檢查與自動重啟腳本
# 作者: Opsers 社群整理
# 用途: 每分鐘檢查一次,異常自動重啟 php-fpm
# ===== 可配置變數 =====
MONITOR_URL="https://127.0.0.1/health.php" # 監控頁面 URL
PHP_FPM_CMD="/usr/local/php/sbin/php-fpm" # php-fpm 執行檔路徑 (支援 start/stop/reload)
RESTART_LOG="/var/log/php-fpm/restart.log" # 重啟記錄
CHECK_LOG="/var/log/php-fpm/check.log" # 正常心跳記錄 (可選)
TIMEOUT=10 # curl 超時秒數
# ======================
# 確保日誌目錄存在
mkdir -p "$(dirname "$RESTART_LOG")" "$(dirname "$CHECK_LOG")"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 發送 HEAD 請求,僅取得 HTTP 狀態碼
HTTP_STATUS=$(curl -s --head --max-time "$TIMEOUT" "$MONITOR_URL" | awk '/^HTTP\// {print $2}')
if [ "$HTTP_STATUS" != "200" ]; then
# 異常:記錄並重啟
echo "[$TIMESTAMP] ALERT: HTTP status=$HTTP_STATUS, restarting php-fpm..." >> "$RESTART_LOG"
$PHP_FPM_CMD restart >> "$RESTART_LOG" 2>&1
# 可選:發送告警郵件 (需配置 mailx/postfix)
# echo "PHP-FPM restarted on $(hostname) at $TIMESTAMP" | mail -s "ALERT: PHP-FPM Restarted" admin@example.com
else
# 正常:可選記錄心跳 (建議註解以減少日誌量)
# echo "[$TIMESTAMP] OK: php-fpm is running (HTTP $HTTP_STATUS)" >> "$CHECK_LOG"
:
fi
chmod +x /usr/local/bin/chk_phpfpm.sh
mkdir -p /var/log/php-fpm
touch /var/log/php-fpm/restart.log /var/log/php-fpm/check.log
chown -R www:www /var/log/php-fpm # 視 php-fpm 執行用戶而定
crontab -e -u root
# 每分鐘執行一次
* * * * * /usr/local/bin/chk_phpfpm.sh
$HTTP_STATUS 為空,條件判斷視為異常,導致每分鐘重啟一次 php-fpm,造成服務抖動、日誌爆增、甚至系統負載飆升。yum install curl -y 或 apt-get install curl -y。| 優化方向 | 實作方式 |
|---|---|
| 避免誤判 | 連續 2-3 次檢查失敗才重啟;檢查多個端點 (如 /health.php、/api/ping) |
| 重啟冷卻期 | 記錄上次重啟時間,間隔 < 5 分鐘不重啟,改發告警 |
| 優雅重啟 | 使用 php-fpm reload (SIGUSR2) 而非 restart,保持現有連線處理完畢 |
| 整合監控系統 | 推送指標至 Prometheus/Zabbix/監控寶,配合 Grafana 視覺化 |
| 容器環境 | K8s 使用 livenessProbe/readinessProbe 替代 crontab 腳本 |
PHP_FPM_CMD 路徑正確、支援 restart 參數 (官方 init.d 腳本支援),或改用 systemctl reload php-fpm / kill -USR2 $PID。