腳本設計目標
- 檢測 MySQL 3306 端口是否監聽
- 驗證實際連線查詢是否正常 (防止假死/阻塞)
- 異常時自動殺掉殭屍進程並重啟服務
- 避免誤殺、重啟風暴、日誌記錄可追蹤
完整腳本 /usr/local/bin/mysql_monitor.sh
#!/bin/bash
# MySQL 狀態檢測與自動恢復腳本
# 依賴: nmap, mysql client
# 建議每 1-5 分鐘透過 crontab 執行一次
# 配置區 ----------------------------------------------------
MYSQL_HOST="localhost"
MYSQL_PORT=3306
MYSQL_USER="monitor_user"
MYSQL_PASS="MonitorPass123!"
MYSQL_BASE="/usr/local/mysql"
CHECK_TIMEOUT=5
LOG_FILE="/var/log/mysql_monitor.log"
# -----------------------------------------------------------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> ${LOG_FILE}
}
# 1. 檢查端口是否監聽 (nmap 掃描本機)
if /usr/bin/nmap -p ${MYSQL_PORT} ${MYSQL_HOST} | grep -q "${MYSQL_PORT}/tcp open"; then
log "端口 ${MYSQL_PORT} 正常監聽"
# 2. 驗證實際連線查詢
if ${MYSQL_BASE}/bin/mysql -u${MYSQL_USER} -p${MYSQL_PASS} \
--connect-timeout=${CHECK_TIMEOUT} \
-e "SHOW DATABASES;" > /dev/null 2>&1; then
log "MySQL 連線查詢正常"
exit 0
else
log "MySQL 連線查詢失敗,嘗試重啟服務"
# 3. 殺掉所有 mysqld 進程 (含殭屍)
pids=$(/bin/ps aux | grep mysqld | grep -v grep | awk '{print $2}')
if [ -n "${pids}" ]; then
log "殺掉進程: ${pids}"
kill -9 ${pids} 2>/dev/null
sleep 3
fi
# 4. 重啟服務
${MYSQL_BASE}/bin/mysqld_safe --user=mysql & > /dev/null
log "MySQL 服務重啟指令已發送"
# 5. 等待啟動並再次驗證
sleep 10
if ${MYSQL_BASE}/bin/mysql -u${MYSQL_USER} -p${MYSQL_PASS} \
--connect-timeout=${CHECK_TIMEOUT} \
-e "SHOW DATABASES;" > /dev/null 2>&1; then
log "重啟後 MySQL 服務恢復正常"
else
log "重啟後 MySQL 服務仍異常,需人工介入"
fi
fi
else
log "端口 ${MYSQL_PORT} 未監聽,直接啟動服務"
${MYSQL_BASE}/bin/mysqld_safe --user=mysql & > /dev/null
log "MySQL 服務啟動指令已發送"
fi
關鍵設計決策解析
為何用 nmap 而非 netstat/ss?
nmap -p 3306 localhost 模擬真實客戶端連線嘗試,驗證防火牆、TCP 堆疊、監聽佇列全鏈路
netstat/ss 僅顯示核心狀態,無法檢測「端口開著但不接受連線」的假死狀態
為何殺進程而非 service restart?
- MySQL 偶發無法正常關閉 (鎖死、檔案描述符洩漏、InnoDB 恢復卡住)
service restart 依賴正常關機流程,可能卡住導致重啟失敗
kill -9 強制釋放資源,確保乾淨重啟
監控帳號最小權限
CREATE USER 'monitor_user'@'localhost' IDENTIFIED BY 'MonitorPass123!';
GRANT USAGE ON *.* TO 'monitor_user'@'localhost';
FLUSH PRIVILEGES;
# 僅需 USAGE 權限 (連線驗證),無任何資料存取權
部署與運維
Crontab 部署 (每 2 分鐘檢測)
# vim /etc/crontab
*/2 * * * * root /usr/local/bin/mysql_monitor.sh
Systemd 服務化 (更穩健)
# /etc/systemd/system/mysql-monitor.service
[Unit]
Description=MySQL Monitor & Auto Recovery
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mysql_monitor.sh
User=root
# /etc/systemd/system/mysql-monitor.timer
[Unit]
Description=Run MySQL Monitor every 2 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=2min
Persistent=true
[Install]
WantedBy=timers.target
# 啟用
systemctl daemon-reload
systemctl enable --now mysql-monitor.timer
日誌輪轉
# /etc/logrotate.d/mysql_monitor
/var/log/mysql_monitor.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 root root
}
進階增強建議
- 多節點檢測:主從雙向檢測、延遲監控 (
Seconds_Behind_Master)
- 告警通知:整合 Telegram/Slack/Email/Webhook,異常即時推送
- 健康度評分:連線數、緩衝池命中率、慢查詢、磁碟空間綜合評分
- 熔斷機制:連續 N 次重啟失敗 → 停止自動重啟、升級人工介入
- 藍綠部署相容:支援多實例、多端口配置陣列