MySQL事務--兩階段提交
MySQL事務協調器
MySQL支援多種儲存引擎,並在MySQL Server層實現Binlog機制來進行主從資料同步。每種儲存引擎相互獨立,使用不同的資料檔案和日誌檔案,當MySQL例項內部一個事務涉及到多個事務儲存引擎表時,需要使用2PC來保證資料一致性。
## 檔案sql\mysqld.cc static int init_server_components() { tc_log = &tc_log_dummy; if (total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log)) { if (opt_bin_log) tc_log = &mysql_bin_log; else tc_log = &tc_log_mmap; } } ## 等價於 static int init_server_components() { tc_log = &tc_log_dummy; if (total_ha_2pc > 0 && opt_bin_log) { tc_log = &mysql_bin_log; } if (total_ha_2pc > 1 && !opt_bin_log) { tc_log = &tc_log_mmap; } }
- 預設使用tc_log_dummy來作為事務協調者
- 當事務引擎超過1個且開啟Binlog,則使用binlog來作為事務協調者。
- 當事務引擎大於1個且未開啟binlog,則使用tc_log_mmap作為事務協調者。
無論tc_log_dummy還是Binlog或tc_log_mmap都基於TC_LOG這個基類來實現:
class TC_LOG { public: virtual int open(const char *opt_name) = 0; virtual void close() = 0; virtual enum_result commit(THD *thd, bool all) = 0; virtual int rollback(THD *thd, bool all) = 0; virtual int prepare(THD *thd, bool all) = 0; };
tc_log_dummy是一個空實現,不會記錄事務日誌。
tc_log_mmap是一個標準的事務協調者實現,它會建立一個名為 tc.log
的日誌並使用作業系統的記憶體對映(memory-map,mmap)機制將內容對映到記憶體中。tc.log
檔案中分為一個一個 PAGE,每個 PAGE 上有多個XID。
binlog同樣基於TC_LOG來實現事務協調者功能,會遞增生成mysql-binlog.xxxxx的檔案,每個檔案中包含多個事務產生的binlog event,並在binlog event中包含XID。
tc_log_mmap和binlog都基於XID來確定事務是否已提交。
InnoDB事務儲存引擎
MySQL儲存引擎會在初始化時將相應方法註冊到MySQL Server層,以InnoDB事務儲存引擎為例,在初始化時會註冊prepare、commit、rollback、recover等函式到MySQL Server層,供事務協調者呼叫。
## 檔案 storage\innobase\handler\ha_innodb.cc
/** Initialize the InnoDB storage engine plugin.
@param[in,out] p InnoDB handlerton
@return error code
@retval 0 on success */
static int innodb_init(void *p) {
handlerton *innobase_hton = (handlerton *)p;
innodb_hton_ptr = innobase_hton;
innobase_hton->commit = innobase_commit;
innobase_hton->rollback = innobase_rollback;
innobase_hton->prepare = innobase_xa_prepare;
innobase_hton->recover = innobase_xa_recover;
}
在使用Binlog作為事務協調器的2PC過程中:
- 在prepare階段,使用MYSQL_BIN_LOG::prepare呼叫InnoDB儲存引擎的innobase_xa_prepare方法,將InnoDB的事務日誌Redo Log持久化。
- 在Commit階段,使用MYSQL_BIN_LOG::commit先將Binlog日誌進行持久化,然後呼叫innobase_commit方法,將事務在InnoDB儲存引擎層進行提交。
MySQL兩階段提交
無論時MySQL 外部XA事務還是內部XA事務,都需要通過兩階段事務提交2PC的方式來保證資料一致性。在大部分的使用場景中,都會開啟MySQL Binlog來進行主從資料同步,同時InnoDB事務儲存引擎成為主流選擇,因此在討論MySQL兩階段提交時更多的會關注在MySQL Server層的Binlog日誌和InnoDB事務日誌(Redo Log)。