主庫定期向心跳表寫入當前時間戳,從庫讀取該值與本地系統時間對比,得出真實延遲秒數,比 Seconds_Behind_Master 更準確(不受長事務、並行複製影響)。
test.heartbeat(主庫建立,自動複製到從庫)monitor(需 REPLICATION CLIENT、SELECT 權限)--daemonize 方式常駐主庫寫入#!/bin/bash # 用法: ck_slave_lag.sh# 例: */1 * * * * /opt/scripts/ck_slave_lag.sh 11 3 /var/log/mysql/slave_lag set -euo pipefail if [ $# -ne 3 ]; then echo "Usage: $0 " exit 1 fi SERVER_ID=$1 MAX_LAG=$2 LOG_DIR=$3 TS=$(date +%Y%m%d_%H%M%S) RETENTION=7 LOG_FILE="${LOG_DIR}/slave_lag_${TS}.log" DETAIL_LOG="${LOG_DIR}/slave_lag_detail_${TS}.log" MAIL_TO="dba@example.com" mkdir -p "${LOG_DIR}" # 1. 單次檢查模式 LAG=$(pt-heartbeat --user=monitor --password=xxx -S /tmp/mysql.sock -D test \ --master-server-id="${SERVER_ID}" --check 2>/dev/null) LAG=${LAG%.*} # 取整數秒 # 2. 判斷是否超閾值 if [ "${LAG}" -gt "${MAX_LAG}" ]; then { echo "=== $(date) $(hostname) ===" echo "Current lag: ${LAG}s (threshold: ${MAX_LAG}s)" echo "Log file: ${LOG_FILE}" } >> "${LOG_FILE}" # 3. 若無監控進程,啟動持續監控守護進程 PT_PID=$(pgrep -f "pt-heartbeat.*--monitor.*--daemonize") if [ -z "${PT_PID}" ]; then echo "Starting monitor daemon..." >> "${LOG_FILE}" pt-heartbeat --user=monitor --password=xxx -S /tmp/mysql.sock -D test \ --master-server-id="${SERVER_ID}" \ --monitor --print-master-server-id \ --daemonize --log="${DETAIL_LOG}" & fi # 4. 發送告警郵件 cat "${LOG_FILE}" | mail -s "MySQL Slave Lag Alert on $(hostname)" "${MAIL_TO}" fi # 5. 守護進程存活超時保護(>30 分鐘強制殺掉,防止日誌爆盤) if [ -n "${PT_PID}" ]; then START_TIME=$(ps -o lstart= -p "${PT_PID}") START_EPOCH=$(date -d "${START_TIME}" +%s) NOW_EPOCH=$(date +%s) if [ $((NOW_EPOCH - START_EPOCH)) -gt 1800 ]; then kill -9 "${PT_PID}" echo "$(date) Killed pt-heartbeat monitor daemon (PID: ${PT_PID}) running > 30min" >> "${LOG_FILE}" fi fi # 6. 清理舊日誌 find "${LOG_DIR}" -name "slave_lag_*" -ctime +${RETENTION} -delete exit 0
參數 說明 --check單次讀取延遲並退出,適合定時任務 --monitor持續監控模式,定期寫入詳細日誌 --daemonize後台守護進程運行 --master-server-id指定主庫 server_id,多主環境必須 --print-master-server-id日誌中輸出主庫 ID,便於多主區分 心跳表結構(自動建立)