MySQL Binlog用于記錄用戶對數據庫操作的結構化查詢語言(Structured Query Language,SQL)語句信息。是MySQL數據庫的二進制日志,可以使用mysqlbin命令查看二進制日志的內容。愛奇藝在會員訂單系統使用到了 MySQL Binlog,用來實現訂單事件驅動。在使用Binlog 后在簡化系統設計的同時幫助系統提升了可用性和數據一致性。
背 景 Binlog 是 MySQL 中一個很重要的日志,主要用于 MySQL 主從間的數據同步復制。正是因為 Binlog 的這項功用,它也被用于 MySQL 向其它類型數據庫同步數據,以及業務流程的事件驅動設計。通過研究分析,我們發現使用 MySQL Binlog 實現事件驅動設計并沒有想象中那么簡單,所以接下來帶大家了解 MySQL 的 Binlog、Redo Log、數據更新內部流程,并通過對這些技術原理的介紹,來分析對業務流程可能造成的問題,以及如何避免這些問題。希望通過本文的解析,能夠幫助大家了解到 MySQL 的一些原理,從而幫助大家能夠更順利地使用 MySQL 這個流行的數據庫技術。
圖中描述了 update 語句執行過程中 MySQL 執行器、InnoDB,以及 Binlog、Redo Log 交互過程(圖中深綠底色的是 MySQL 執行器負責的階段,淺綠底色是 InnoDB 負責的階段)
問題解析 從上面對 MySQL 原理的介紹我們得知,寫 Binlog 發生在事務提交階段,但是 MySQL 因為在 Server 層和存儲引擎層都引入了不同的日志結構,從而引入了兩階段提交。Binlog 的寫入發生在存儲引擎真正提交事務之前,這導致理論上通過 Binlog 同步數據的系統(MySQL 從庫、其它數據庫或業務系統)有可能早于 MySQL 主庫使最新提交的數據生效。
所以上面提到的訂單履約服務在收到基于 Binlog 的訂單支付事件后卻查到相應訂單是未支付的,原因很可能是訂單履約服務在查詢數據時,訂單支付數據更新操作在 MySQL 內部尚未徹底完成事務的提交。
我們通過開發驗證程序重現了這一現象。驗證程序接收到事務提交完成后的完整 Binlog 時會再次在 MySQL 主庫上查詢對應的記錄,結果會有一定概覽獲得事務提交前的數據。