一、為什么要保證binlog和redo log提交的順序一致
MySQL為了保證master和slave的數(shù)據(jù)一致性,就必須保證binlog和InnoDB redo日志的一致性(因?yàn)閭鋷焱ㄟ^二進(jìn)制日志重放主庫提交的事務(wù),而主庫binlog寫入在commit之前,如果寫完binlog主庫crash,再次啟動(dòng)時(shí)會(huì)回滾事務(wù)。但此時(shí)從庫已經(jīng)執(zhí)行,則會(huì)造成主備數(shù)據(jù)不一致)。所以在開啟Binlog后,如何保證binlog和InnoDB redo日志的一致性呢?為此,MySQL引入二階段提交(two phase commit or 2pc),MySQL內(nèi)部會(huì)自動(dòng)將普通事務(wù)當(dāng)做一個(gè)XA事務(wù)(內(nèi)部分布式事物)來處理:
– 自動(dòng)為每個(gè)事務(wù)分配一個(gè)少數(shù)的ID(XID)。
– COMMIT會(huì)被自動(dòng)的分成Prepare和Commit兩個(gè)階段。
– Binlog會(huì)被當(dāng)做事務(wù)協(xié)調(diào)者(Transaction Coordinator),Binlog Event會(huì)被當(dāng)做協(xié)調(diào)者日志。
Binlog在2PC中充當(dāng)了事務(wù)的協(xié)調(diào)者(Transaction Coordinator)。由Binlog來通知InnoDB引擎來執(zhí)行prepare,commit或者rollback的步驟。
事務(wù)的提交主要分為兩個(gè)主要步驟:
1. 準(zhǔn)備階段(Storage Engine(InnoDB) Transaction Prepare Phase)
此時(shí)SQL已經(jīng)成功執(zhí)行,并生成xid信息及redo和undo的內(nèi)存日志。然后調(diào)用prepare方法完成名列前茅階段,papare方法實(shí)際上什么也沒做,將事務(wù)狀態(tài)設(shè)為TRX_PREPARED,并將redo log刷磁盤。
2. 提交階段(Storage Engine(InnoDB)Commit Phase)
2.1 記錄協(xié)調(diào)者日志,即Binlog日志。
如果事務(wù)涉及的所有存儲(chǔ)引擎的prepare都執(zhí)行成功,則調(diào)用TC_LOG_BINLOG::log_xid方法將SQL語句寫到binlog(write()將binary log內(nèi)存日志數(shù)據(jù)寫入文件系統(tǒng)緩存,fsync()將binary log文件系統(tǒng)緩存日志數(shù)據(jù)永久寫入磁盤)。此時(shí),事務(wù)已經(jīng)鐵定要提交了。否則,調(diào)用ha_rollback_trans方法回滾事務(wù),而SQL語句實(shí)際上也不會(huì)寫到binlog。
2.2 告訴引擎做commit。
最后,調(diào)用引擎的commit完成事務(wù)的提交。會(huì)清除undo信息,刷redo日志,將事務(wù)設(shè)為TRX_NOT_STARTED狀態(tài)。
PS:記錄Binlog是在InnoDB引擎Prepare(即Redo Log寫入磁盤)之后,這點(diǎn)至關(guān)重要。
由上面的二階段提交流程可以看出,一旦步驟2中的操作完成,就確保了事務(wù)的提交,即使在執(zhí)行步驟3時(shí)數(shù)據(jù)庫發(fā)送了宕機(jī)。此外需要注意的是,每個(gè)步驟都需要進(jìn)行一次fsync操作才能保證上下兩層數(shù)據(jù)的一致性。步驟2的fsync參數(shù)由sync_binlog=1控制,步驟3的fsync由參數(shù)innodb_flush_log_at_trx_commit=1控制,俗稱“雙1”,是保證CrashSAFe的根本。
延伸閱讀:
二、關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)組織
關(guān)系型數(shù)據(jù)庫中,數(shù)據(jù)組織涉及到兩個(gè)最基本的結(jié)構(gòu):表與索引。表中存儲(chǔ)的是完整記錄,一般有兩種組織形式:堆表(所有的記錄無序存儲(chǔ)),或者是聚簇索引表(所有的記錄,按照記錄主鍵進(jìn)行排序存儲(chǔ))。索引中存儲(chǔ)的是完整記錄的一個(gè)子集,用于加速記錄的查詢速度,索引的組織形式,一般均為B+樹結(jié)構(gòu)。