面對數月累積的 Binlog,單檔手工 mysqlbinlog | grep 效率極低。本文提供生產級 Shell 腳本,實現 Binlog 批量解碼、關鍵字多條件過濾、結果分級記錄,快速定位「莫名其妙寫入」的來源。
AD_ADVERTISEMENT 表 AD_LINK 欄位出現異常值 ad_init_user,業務邏輯不應寫入此值。mysqlbinlog --base64-output=DECODE-ROWS -v binlog_file
# --base64-output=DECODE-ROWS : 將 ROW 格式 Binlog 解碼為可讀偽 SQL (含列名、值)
# -v (--verbose) : 顯示更多細節 (ROW 事件解碼必加)
# --start-datetime / --stop-datetime : 時間範圍過濾 (若知大約時間)
#!/bin/bash
# find_binlog_event.sh
# 用法: ./find_binlog_event.sh [搜尋關鍵字1] [關鍵字2] ...
set -euo pipefail
BINLOG_SOURCE_DIR="/home/data/mysql/binlog"
WORK_DIR="/tmp/binlog_search_$(date +%s)"
KEYWORDS=("$@") # 從命令列傳入關鍵字,如: AD_ADVERTISEMENT AD_LINK ad_init_user
MYSQLBINLOG="/usr/local/mysql/bin/mysqlbinlog"
# 參數檢查
if [ ${#KEYWORDS[@]} -eq 0 ]; then
echo "Usage: $0 [keyword2] ..."
exit 1
fi
# 建立工作目錄
mkdir -p "$WORK_DIR"
cd "$WORK_DIR"
# 複製 Binlog (避免影響主庫磁碟 IO,建議從備份機複製)
echo "[$(date)] Copying binlogs from $BINLOG_SOURCE_DIR ..."
cp "$BINLOG_SOURCE_DIR"/mysql-bin.* . 2>/dev/null || { echo "No binlogs found"; exit 1; }
# 結果檔案
SUMMARY_LOG="search_summary.log"
DETAIL_LOG="search_detail.log"
> "$SUMMARY_LOG"
> "$DETAIL_LOG"
# 構建 grep 管線 (多關鍵字 AND 邏輯)
GREP_PIPE="grep ${KEYWORDS[0]}"
for kw in "${KEYWORDS[@]:1}"; do
GREP_PIPE="$GREP_PIPE | grep $kw"
done
echo "[$(date)] Starting scan with keywords: ${KEYWORDS[*]}"
echo "Grep pipeline: $GREP_PIPE"
# 遍歷所有 Binlog 檔案
for binlog in mysql-bin.*; do
echo "[$(date)] Scanning $binlog ..."
echo "=== BEGIN $binlog ===" >> "$SUMMARY_LOG"
echo "$binlog" >> "$SUMMARY_LOG"
# 執行解碼並過濾,寫入摘要與詳細日誌
eval "$MYSQLBINLOG --base64-output=DECODE-ROWS -v $binlog | $GREP_PIPE" >> "$SUMMARY_LOG" 2>&1
eval "$MYSQLBINLOG --base64-output=DECODE-ROWS -v $binlog | $GREP_PIPE" >> "$DETAIL_LOG" 2>&1
echo "=== END $binlog ===" >> "$SUMMARY_LOG"
echo "" >> "$SUMMARY_LOG"
done
echo "[$(date)] Scan complete."
echo "Summary log: $WORK_DIR/$SUMMARY_LOG"
echo "Detail log: $WORK_DIR/$DETAIL_LOG"
# 快速判斷是否有結果
if [ -s "$DETAIL_LOG" ]; then
echo "✓ FOUND MATCHES in detail log"
head -20 "$DETAIL_LOG"
else
echo "✗ NO MATCHES in current binlog retention (check older backups)"
fi
$ ./find_binlog_event.sh AD_ADVERTISEMENT AD_LINK ad_init_user
[2024-01-15 10:30:00] Copying binlogs from /home/data/mysql/binlog ...
[2024-01-15 10:30:05] Starting scan with keywords: AD_ADVERTISEMENT AD_LINK ad_init_user
[2024-01-15 10:35:22] Scanning mysql-bin.000001 ...
...
[2024-01-15 10:45:10] Scan complete.
Summary log: /tmp/binlog_search_1705312200/search_summary.log
Detail log: /tmp/binlog_search_1705312200/search_detail.log
✗ NO MATCHES in current binlog retention (check older backups)
$ ls -lh /tmp/binlog_search_1705312200/
-rw-r--r-- 1 root root 33K Jan 15 10:45 search_summary.log
-rw-r--r-- 1 root root 0 Jan 15 10:45 search_detail.log # 0 字節 = 無匹配
結論:近 2 個月 Binlog 無此異常寫入,需檢查更早備份 (如月度全備解壓後的 Binlog)。
--start-datetime='2024-01-01 00:00:00' --stop-datetime='2024-01-15 23:59:59' 大幅減少解碼量。xargs -P 4 或 GNU parallel 並行解碼多檔 (CPU 密集型,視核心數而定)。mysqlbinlog -R -h master_host -u user -p --start-datetime=... mysql-bin.000001 直接從主庫讀取,避免複製檔案 (需 --read-from-remote-server)。| 格式 | 搜尋難度 | 說明 |
|---|---|---|
| STATEMENT | 低 | 原始 SQL 可直接 grep,但動態 SQL (NOW(), UUID()) 難追蹤具體值 |
| ROW | 高 | 必須 --base64-output=DECODE-ROWS -v 解碼,解碼慢、輸出大,但能見真實列值 |
| MIXED | 中 | 部分 STATEMENT 部分 ROW,需統一用 ROW 解碼參數 |
生產強制 ROW 格式 (binlog_format=ROW),雖搜尋需解碼,但數據完整性最高、主從一致性最強。
Binlog 全量搜尋核心流程:**複製檔案 → 並行解碼 (DECODE-ROWS -v) → 多關鍵字管線過濾 → 分級記錄 (摘要/詳情) → 結果判讀**。腳本化、參數化、並行化、索引化是從「大海撈針」走向「精準定位」的關鍵演進。