故障分析 | MySQL 數據”丟失”事件之 binlog 解析應用一則

作者:餘振興
愛可生 DBA 團隊成員,熟悉 Oracle、MySQL、MongoDB、Redis,最近在盤 TiDB,擅長架構設計、故障診斷、數據遷移、災備構建等等。負責處理客戶 MySQL 及我司自研 DMP 數據庫管理平臺日常運維中的問題。熱衷技術分享、編寫技術文檔。
本文來源:原創投稿
*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。

事件背景

客戶反饋在晚間數據跑批後,查詢相關表的數據時,發現該表的部分數據在數據庫中不存在,從應用跑批的日誌來看,跑批未報錯,且可查到日誌中明確顯示當時那批數據已插入到數據庫中,需要幫忙分析這批數據丟失的原因。

備註:考慮信息敏感性,以下分析場景測試環境模擬,相關數據做以下說明

  • 涉及的庫表爲 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,找到是否有對該條記錄做DELETEUPDATE操作即可

3. 解析binlog查看對這張表的修改操作

過濾出哪些binlog對該表做了DELETEUPDATE

## 這裏我通過已知的故障時間區間將涉及的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. 排除一些特殊操作的可能性

  1. 在插入這條數據時,主庫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解析技巧

    1. 儘可能在從庫解析,避免對主庫造成影響

    2. 先粗略定位涉及相關的庫表操作的binlog,再單獨解析對應的binlog中的數據

    3. 在解析DDL時無需加-v輸出詳細信息(加快解析速度)

    4. 如果開啓了binlog_rows_query_log_events參數,需要用-vv參數纔可顯示具體的SQL語句


    文章推薦:

    技術分享 | MySQL Shell import_table 數據導入

    技術分享 | MySQL Load Data 的多種用法



    社區近期動態




    本文關鍵字:#mysqlbinlog# #binlog解析#
      點一下“閱讀原文”瞭解更多資訊

    本文分享自微信公衆號 - 愛可生開源社區(ActiontechOSS)。
    如有侵權,請聯繫 [email protected] 刪除。
    本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章