事件背景
客戶反饋在晚間數據跑批後,查詢相關表的數據時,發現該表的部分數據在數據庫中不存在,從應用跑批的日誌來看,跑批未報錯,且可查到日誌中明確顯示當時那批數據已插入到數據庫中,需要幫忙分析這批數據丟失的原因。
備註:考慮信息敏感性,以下分析場景測試環境模擬,相關數據做以下說明
-
涉及的庫表爲 demo.t_dba_info
表 -
丟失的數據爲 insert into t_dba_info(name,age) values('zhenxing',20);
這條記錄
故障分析
1. 先登錄數據庫確認該條記錄是否存在
顯然,數據確實如客戶所說,在數據庫中不存在
2. 確認該條數據丟失的時間區間並解析binlog
這裏我爲模擬環境,直接在主庫解析,生產環境建議都在從庫解析避免對主庫造成影響
BINLOG_LIST='mysql-bin.000002 mysql-bin.000003 mysql-bin.000004 mysql-bin.000005 mysql-bin.000006 mysql-bin.000007'
for binlog in ${BINLOG_LIST}
do
echo "====== ${binlog}"
mysqlbinlog -vv ${binlog}|grep -iEw "zhenxing"
done
可以看到我們通過解析並搜索
zhenxing
這條記錄,確實發現數據插入了數據庫中,所以接下來從常規的思路來說我們只需要繼續解析binlog,找到是否有對該條記錄做DELETE
或UPDATE
操作即可
3. 解析binlog查看對這張表的修改操作
過濾出哪些binlog對該表做了
DELETE
或UPDATE
## 這裏我通過已知的故障時間區間將涉及的binlog列出來做循環解析
BINLOG_LIST='mysql-bin.000002 mysql-bin.000003 mysql-bin.000004 mysql-bin.000005 mysql-bin.000006 mysql-bin.000007'
for binlog in ${BINLOG_LIST}
do
echo "====== ${binlog}"
mysqlbinlog --no-defaults --base64-output=decode-rows -vv ${binlog} | awk '/###/ {if($0~/UPDATE|INSERT|DELETE/)count[$2" "$NF]++}END{for(i in count) print i,"\t",count[i]}' | column -t | sort -k2nr|grep -i t_dba_info
done
通過解析binlog可以看到,對該表的操作只有mysql-bin.000006這個binlog文件有2次UPDATE操作,其他都是INSERT,接下來我們只需要繼續解析這個mysql-bin.000006文件並搜索看是否對zhenxing這條記錄是否做了修改即可
4. 解析定位的binlog
## 用最簡單的命令直接解析並搜索對demo.t_dba_info表插入的zhenxing這條記錄
[root@10-186-61-100 binlog]# mysqlbinlog -vv mysql-bin.000006|less
通過解析發現這個binlog文件做對demo.t_dba_info表的UPDATE操作並不是針對zhenxing這條記錄的,分析到這裏發現比較迷惑了,數據明明插入了,也沒做修改怎麼就不見了,難道做了一些特殊操作
5. 排除一些特殊操作的可能性
-
在插入這條數據時,主庫binlog明確有記錄,那是否有可能在刪除這條記錄時做了 set session sql_log_bin=off
不記錄binlog
-
這個只需在從庫查詢下這條記錄是否存在即可初步排除,客戶生產環境是一主多從的架構,從庫均沒有這條記錄存在, 可能性被排除
有沒有可能這張表除了DML行爲,還有DDL行爲,如重建了,但重建後這批數據沒有被重新插入該表,於是嘗試解析binlog看對該表的DDL操作行爲是否存在
BINLOG_LIST='mysql-bin.000002 mysql-bin.000003 mysql-bin.000004 mysql-bin.000005 mysql-bin.000006 mysql-bin.000007'
for binlog in ${BINLOG_LIST}
do
echo "====== ${binlog}"
mysqlbinlog ${binlog}|egrep -iEw "truncate|create|drop"
done
發現了一些端倪,在mysql-bin.000004中有對該表的2次truncate操作,等等,好像發現了什麼,那條丟失的數據也是在這個mysql-bin.000004文件中,梳理下邏輯,難道那條記錄在2次truncate之間,於是單獨對這個binlog做詳細解析,得到以下信息
#211211 14:52:47 truncate table t_dba_info
#211211 14:53:00 insert into t_dba_info(name,age) values('zhenxing',20)
#211211 14:53:18 truncate table t_dba_info
到此基本瞭解了這條記錄爲何會詭異丟失了,與客戶確認跑批灌數據的邏輯,瞭解到會對該表做truncate,但由於誤操作
,在跑批開始後,又觸發了一輪truncate行爲,導致已經插入到該表的部分數據再次被清理了,也就導致了在解析binlog時部分記錄丟失了,但並未觀測到有刪除的行爲,而是被truncate方式清理.
6. 故障總結
本文是對binlog解析的一個實踐案例,binlog記錄的信息非常多,可以對binlog進行不同維度的解析,同時binlog在線上環境的配置使用上也有着一些技巧,如本案例中,線上環境因爲是規範化部署,參數設置合理,不會由於單個binlog文件過大導致binlog解析時間過長,以及如binlog_rows_query_log_events參數的開啓,使得在row模式下也可以明確記錄下具體的SQL語句
max_binlog_size = 250M
binlog_rows_query_log_events = 1
備註
:雖然binlog記錄的信息足夠多,但當故障原因定位後,由於其並未記錄對該操作的IP及用戶
信息,如果不開審計,也只能知道發生了該行爲,但無法具體定位觸發該行爲的"人".
7. binlog解析技巧
儘可能在從庫解析,避免對主庫造成影響
先粗略定位涉及相關的庫表操作的binlog,再單獨解析對應的binlog中的數據
在解析DDL時無需加-v輸出詳細信息(加快解析速度)
如果開啓了binlog_rows_query_log_events參數,需要用-vv參數纔可顯示具體的SQL語句
文章推薦:
技術分享 | MySQL Shell import_table 數據導入
社區近期動態
本文分享自微信公衆號 - 愛可生開源社區(ActiontechOSS)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。