VPS 資源有限 (1-2GB 記憶體常見),MySQL、PHP-FPM、Nginx 等服務在流量突增或記憶體洩漏時極易耗盡資源導致當機。本文提供兩支生產級監控腳本:依比例監控 適合容器/動態環境,依絕對值監控 適合固定規格 VPS,並詳細說明參數調校、部署驗證、常見錯誤排查。
auto_reboot.sh)適用場景: 容器、雲主機、記憶體總量可變環境。當服務記憶體佔比超過閾值 或 系統負載過高 時,重啟指定服務。
#!/bin/bash
# auto_reboot.sh - 依比例監控版
# 部署路徑建議:/usr/local/sbin/auto_reboot.sh
# crontab: * * * * * /usr/local/sbin/auto_reboot.sh >/dev/null 2>&1
# ========== 使用者配置區 ==========
# 服務記憶體佔用最大百分比 (超過則重啟該服務)
PID_MEM_MAX=85
# 系統負載 1 分鐘平均值最大值 (超過則重啟服務)
SYS_LOAD_MAX=3.0
# 監控的服務名稱 (systemd service name 或進程關鍵字,空格分隔)
NAME_LIST="php-fpm mysqld nginx"
# 記憶體資訊來源 (通常免改)
MEM_INFO="/proc/meminfo"
# ====================================
# 取得系統總記憶體 (KB)
TOTAL_MEM=$(awk '/MemTotal/ {print $2}' $MEM_INFO)
# 取得系統可用記憶體 (KB) - 含 buffers/cache
AVAIL_MEM=$(awk '/MemAvailable/ {print $2}' $MEM_INFO)
# 若無 MemAvailable (舊核心),退而求其次用 MemFree+Buffers+Cached
if [ -z "$AVAIL_MEM" ]; then
FREE_MEM=$(awk '/MemFree/ {print $2}' $MEM_INFO)
BUFFERS=$(awk '/Buffers/ {print $2}' $MEM_INFO)
CACHED=$(awk '/^Cached/ {print $2}' $MEM_INFO)
AVAIL_MEM=$((FREE_MEM + BUFFERS + CACHED))
fi
# 計算系統記憶體使用率 (%)
MEM_USAGE_PCT=$(awk "BEGIN {printf \"%.0f\", (($TOTAL_MEM - $AVAIL_MEM) * 100) / $TOTAL_MEM}")
# 取得系統負載 (1 分鐘)
SYS_LOAD=$(awk '{print $1}' /proc/loadavg)
# 判斷是否觸發重啟條件
TRIGGER=0
if [ $MEM_USAGE_PCT -ge $PID_MEM_MAX ]; then
echo "[$(date)] Memory usage ${MEM_USAGE_PCT}% >= ${PID_MEM_MAX}%, triggering restart"
TRIGGER=1
fi
if (( $(echo "$SYS_LOAD > $SYS_LOAD_MAX" | bc -l) )); then
echo "[$(date)] System load ${SYS_LOAD} > ${SYS_LOAD_MAX}, triggering restart"
TRIGGER=1
fi
if [ $TRIGGER -eq 1 ]; then
for SVC in $NAME_LIST; do
echo "[$(date)] Restarting service: $SVC"
systemctl restart $SVC 2>/dev/null || service $SVC restart 2>/dev/null
sleep 2
done
fi
check_reboot.sh)適用場景: 固定規格 VPS (如 1GB/2GB 記憶體),根據實際剩餘 MB 數決定動作。
#!/bin/bash
# check_reboot.sh - 依絕對值監控版
# 部署路徑建議:/usr/local/sbin/check_reboot.sh
# crontab: * * * * * /usr/local/sbin/check_reboot.sh >/dev/null 2>&1
# ========== 使用者配置區 ==========
# 最小剩餘記憶體 (MB) - 低於此值視為危險
FREE_MEM_MIN=100
# 系統負載 1 分鐘最大值
SYS_LOAD_MAX=3.0
# 重啟服務所需最小剩餘記憶體 (MB) - 低於此值不嘗試重啟(防止重啟失敗更糟)
RESTART_FREE_MEM_MIN=200
# 監控的服務名稱
NAME_LIST="httpd mysqld php-fpm nginx"
# ====================================
# 取得剩餘記憶體 (MB)
FREE_MEM_MB=$(awk '/MemAvailable/ {printf "%.0f", $2/1024}' /proc/meminfo)
if [ -z "$FREE_MEM_MB" ] || [ $FREE_MEM_MB -eq 0 ]; then
FREE_MEM_MB=$(awk '/MemFree/ {free=$2} /Buffers/ {buf=$2} /^Cached/ {cac=$2} END {printf "%.0f", (free+buf+cac)/1024}' /proc/meminfo)
fi
# 取得系統負載
SYS_LOAD=$(awk '{print $1}' /proc/loadavg)
echo "[$(date)] FreeMem=${FREE_MEM_MB}MB Load=${SYS_LOAD}"
# 記憶體極度不足,不嘗試重啟,僅記錄告警 (需人工/監控系統介入)
if [ $FREE_MEM_MB -lt $FREE_MEM_MIN ]; then
echo "[$(date)] CRITICAL: Free memory ${FREE_MEM_MB}MB < ${FREE_MEM_MIN}MB, skipping auto-restart to avoid OOM"
# 這裡可加入發送告警郵件/釘釘/Telegram 邏輯
exit 1
fi
# 負載過高或記憶體偏低但尚可重啟
TRIGGER=0
if (( $(echo "$SYS_LOAD > $SYS_LOAD_MAX" | bc -l) )); then
echo "[$(date)] Load ${SYS_LOAD} > ${SYS_LOAD_MAX}"
TRIGGER=1
fi
if [ $FREE_MEM_MB -lt $RESTART_FREE_MEM_MIN ]; then
echo "[$(date)] FreeMem ${FREE_MEM_MB}MB < RestartMin ${RESTART_FREE_MEM_MIN}MB"
TRIGGER=1
fi
if [ $TRIGGER -eq 1 ]; then
for SVC in $NAME_LIST; do
echo "[$(date)] Restarting: $SVC"
systemctl restart $SVC 2>/dev/null || service $SVC restart 2>/dev/null
sleep 3
done
fi
mkdir -p /usr/local/sbin
vim /usr/local/sbin/auto_reboot.sh # 貼上腳本一內容
vim /usr/local/sbin/check_reboot.sh # 貼上腳本二內容
chmod +x /usr/local/sbin/auto_reboot.sh /usr/local/sbin/check_reboot.sh
bc 已安裝 (浮點比較需用):
which bc || yum -y install bc # CentOS/RHEL
# apt-get install -y bc # Debian/Ubuntu
bash -n /usr/local/sbin/auto_reboot.sh
bash -n /usr/local/sbin/check_reboot.sh
/usr/local/sbin/auto_reboot.sh # 應無輸出 (正常情況)
/usr/local/sbin/check_reboot.sh # 輸出當前資源狀態
crontab -e
# 每分鐘執行一次,標準輸出/錯誤導向 /dev/null (或記錄檔)
* * * * * /usr/local/sbin/auto_reboot.sh >>/var/log/auto_reboot.log 2>&1
# * * * * * /usr/local/sbin/check_reboot.sh >>/var/log/check_reboot.log 2>&1
注意: crontab 中 * 之間用 空格 分隔,非 Tab;路徑必須為絕對路徑。
tail -f /var/log/auto_reboot.log
# 觀察每分鐘是否有紀錄
| 參數 | 1GB VPS 建議 | 2GB VPS 建議 | 4GB+ VPS 建議 |
|---|---|---|---|
| PID_MEM_MAX | 80% | 85% | 90% |
| SYS_LOAD_MAX | 1.0 (單核) / 2.0 (雙核) | 2.0 / 4.0 | 核心數 * 0.7 |
| FREE_MEM_MIN | 80MB | 150MB | 300MB |
| RESTART_FREE_MEM_MIN | 150MB | 300MB | 500MB |
在腳本 TRIGGER=1 區塊或 CRITICAL 區塊加入:
# 發送 Telegram Bot 通知
curl -s -X POST "https://api.telegram.org/bot/sendMessage" \
-d chat_id= \
-d text="🚨 VPS Alert: $(hostname) - Service restart triggered. Load: $SYS_LOAD, FreeMem: ${FREE_MEM_MB}MB" \
>/dev/null
自動重啟腳本是**「止血」而非「治本」**。長期穩定仍需:優化 SQL 查詢、啟用 PHP OpCache、配置 Nginx fastcgi/fastcgi_cache、限制並發連線、升級硬體資源。建議將腳本納入基礎設施即代碼管理,配合監控系統 (Prometheus+Alertmanager) 實現「自動止血 + 人工根治」閉環。