mysql之 事務prepare 與 commit 階段分析
開啟binlog選項後,執行事務提交命令時,就會進入兩階段提交模式。兩階段提交分為prepare階段和commit兩個階段。流程如下 :這裡面涉及到兩個重要的引數:innodb_flush_log_at_trx_commit和sync_binlog,引數可以設定不同的值,具體可以檢視mysql的幫助手冊。我這裡設定的是雙一模式(innodb_flush_log_at_trx_commit=1,sync_binlog=1),不同的模式區別在於,寫檔案呼叫write和落盤fsync呼叫的頻率不同,所導致的後果是mysqld 或 os crash後,不嚴格的設定可能會丟失事務的更新。雙一模式是最嚴格的模式,這種設定情況下,單機在任何情況下不會丟失事務更新。
prepare階段:
1.設定undo state=TRX_UNDO_PREPARED; //trx_undo_set_state_at_prepare呼叫
2.刷事務更新產生的redo日誌;【步驟1產生的redo日誌也會刷入】
commit階段:
1.將事務產生的binlog寫入檔案,刷入磁碟;
2.設定undo頁的狀態,置為TRX_UNDO_TO_FREE或TRX_UNDO_TO_PURGE; // trx_undo_set_state_at_finish呼叫
3.記錄事務對應的binlog偏移,寫入系統表空間; //trx_sys_update_mysql_binlog_offset呼叫
下面這部分是我抽象出來的原始碼呼叫部分,大家可以通過單步除錯方式,在關鍵函式中設定斷點,來詳細瞭解這個過程。
===========
prepare階段
===========
MYSQL_BIN_LOG::prepare
ha_prepare_low
{
engine:
binlog_prepare
innobase_xa_prepare
mysql:
trx_prepare_for_mysql
{
1.trx_undo_set_state_at_prepare //設定undo段的標記為TRX_UNDO_PREPARED
2.設定事務狀態為TRX_STATE_PREPARED
3.trx_flush_log_if_needed //將產生的redolog刷入磁碟
}
}
============
commit階段
============
MYSQL_BIN_LOG::commit
ordered_commit
{
1.FLUSH_STAGE
flush_cache_to_file // 刷binlog
2.SYNC_STAGE
sync_binlog_file //Call fsync() to sync the file to disk.
3.COMMIT_STAGE
ha_commit_low
{
binlog_commit
innobase_commit
trx_commit(trx)
{
trx_write_serialisation_history(trx, mtr); //更新binlog位點,設定undo狀態
trx_commit_in_memory(trx, lsn); //釋放鎖資源,清理儲存點列表,清理回滾段
}
}
}
mysqld可能在任何情況下crash,os也有可能出現問題,另外若機器掉電,mysqld也會同樣掛掉。但是即使這樣,mysql仍然能保證資料庫的一致性。接下來,我會結合上述流程,分析二階段提交如何保證這點的。下面給出幾種常見的場景,
1.prepare階段,redo log落盤前,mysqld crash
2.prepare階段,redo log落盤後,binlog落盤前,mysqld crash
3.commit階段,binlog落盤後,mysqld crash
對於第一種情況,由於redo沒有落盤,毫無疑問,事務的更新肯定沒有寫入磁碟,資料庫的一致性受影響;對於第二種情況,這時候redo log寫入完成,但binlog還未寫入,事務處於TRX_STATE_PREPARED狀態,這是提交還是回滾呢?對於第三種情況,此時,redo log和binlog都已經落盤,只是undo狀態沒有更新,這種情況也應該提交,因為redo log和binlog已經一致了,當然這只是我的假設,需要通過原始碼邏輯來驗證。
下面給出了mysqld異常重啟後的執行邏輯以及關鍵的原始碼。對於第三種情況,我們可以蒐集到未提交事務的binlog event,所以需要提交,與我們假設相符;而對於第二種情況,由於binlog未寫入,需要通過執行回滾操作來保證資料庫的一致性。
異常重啟後,如何判斷事務該提交還是回滾
1.讀binlog日誌,獲取崩潰時沒有提交的event; //info->commit_list中含有該元素
2.若存在,則對應的事務要提交;否則需要回滾。
判斷事務提交或回滾原始碼如下:
上面討論了兩階段提交的基本流程,以及伺服器異常crash後,mysql如何重啟恢復保證binlog和資料的一致性。簡而言之,對於異常的xa事務,若binlog已落盤,則事務應該提交;binlog未落盤,則事務就應該回滾。由於這塊涉及到的原始碼較多,我也沒有看完所有原始碼,如有不正確的地方,歡迎指正。
//異常重啟後,回滾流程
innobase_rollback_by_xid
rollback_by_xid
trx_rollback_resurrected
trx_rollback_active
row_undo
{
//從回滾頁獲取undo記錄
//分析undo記錄型別
if (insert)
row_undo_ins
else
row_undo_mod
}
//異常重啟後,提交流程
commit_by_xid
trx_commit_for_mysql
//寫binlog介面
handler.cc:binlog_log_row
sql/binlog.cc:commit
mysys/my_sync:my_sync
sql/binlog.cc:sync_binlog_file
handler/ha_innodb.cc:innobase_xa_prepare
轉:https://www.cnblogs.com/yuyue2014/p/4738007.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31383567/viewspace-2217541/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 分散式事務--兩階段提交(2PC-Prepare/Commit)分散式MIT
- MySQL事務提交的三個階段介紹MySql
- 分散式事務(二)之兩階段提交分散式
- mysql之鎖與事務MySql
- vitess兩階段提交事務Vite
- 三階段提交(Three-phase commit)MIT
- 分散式:分散式事務(CAP、兩階段提交、三階段提交)分散式
- Flink sql 之 兩階段聚合與 TwoStageOptimizedAggregateRule(原始碼分析)SQLZed原始碼
- React原始碼解析之Commit第一子階段「before mutation」React原始碼MIT
- 分散式事務(二)之三階段提交分散式
- MySQL事務與鎖MySql
- MySQL高階12-事務原理MySql
- MySQL事務細枝末節總結與分析[更新]MySql
- MySQL事務與併發MySql
- 資料庫事務與 MySQL 事務總結資料庫MySql
- 《MySQL 進階篇》十九:事務日誌MySql
- 分散式事務之Spring事務與JMS事務(二)分散式Spring
- [Mysql]兩階段提交MySql
- mySQL多表查詢與事務MySql
- MySQL入門--事務與鎖MySql
- mysql鎖與事務總結MySql
- 測試階段注意事項
- pxc 事務pre-commit狀態阻塞MIT
- 分散式事務的兩階段提交和三階段提交分別有什麼優缺點?分散式
- MySQL資料庫6:Go與MySQL事務MySql資料庫Go
- MySQL(一):MySQL資料庫事務與鎖MySql資料庫
- 【MySQL】資料庫事務深入分析MySql資料庫
- TCC和兩階段分散式事務處理的區別分散式
- 分散式事務處理兩階段提交機制和原理分散式
- .NetCore中使用分散式事務DTM的二階段訊息NetCore分散式
- RocketMQ與MYSQL事務訊息整合MQMySql
- MySQL索引、事務與儲存引擎MySql索引儲存引擎
- PHP基礎之與MySQL那些事PHPMySql
- Go 語言操作 MySQL 之 事務操作GoMySql
- 分散式事務之資料庫事務與JDBC事務實現(一)分散式資料庫JDBC
- mysql事務MySql
- MySQL 事務MySql
- MySQL:COUNT(*) profile optimizing階段慢MySql