深入理解InnoDB -- 事務(wù)篇

事務(wù)的定義

事務(wù)的基本要素(ACID)
原子性:Atomicity匀油,整個數(shù)據(jù)庫事務(wù)是不可分割的工作單位
一致性:Consistency敌蚜,事務(wù)將數(shù)據(jù)庫從一種狀態(tài)轉(zhuǎn)變?yōu)橄乱环N一致的狀態(tài)
隔離性:Isolation齐媒,每個讀寫事務(wù)的對象對其他事務(wù)的操作對象能相互分離
持久性:Durability喻括,事務(wù)一旦提交唬血,其結(jié)果是永久性的

事務(wù)的并發(fā)問題
臟讀:事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù)拷恨,然后B回滾操作腕侄,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)
不可重復(fù)讀:事務(wù) A 多次讀取同一數(shù)據(jù),期間事務(wù) B對數(shù)據(jù)作了更新并提交酸茴,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時噪舀,結(jié)果 不一致。
幻讀:事務(wù) A 多次同一條件查詢界逛,期間事務(wù)B刪除或插入了滿足條件的數(shù)據(jù)息拜,導(dǎo)致事務(wù)A多次讀取的結(jié)果集不一致。

SQL標(biāo)準(zhǔn)定義的隔離級別為:

事務(wù)隔離級別 描述 臟讀 不可重復(fù)讀 幻讀
READ UNCOMMITTED 一個事務(wù)會讀到另一個未提交事務(wù)修改過的數(shù)據(jù)赞别。
READ COMMITTED 一個事務(wù)只能讀到另一個已經(jīng)提交的事務(wù)修改過的數(shù)據(jù)仿滔。
REPEATABLE READ 一個事務(wù)只能讀到另一個已經(jīng)提交的事務(wù)修改過的數(shù)據(jù)崎页,而且該事務(wù)第一次讀過某條記錄后飒焦,即使其他事務(wù)修改了該記錄的值并且提交牺荠,該事務(wù)之后再讀該條記錄時休雌,讀到的仍是第一次讀到的值挑辆。
SERIALIZABLE 事務(wù)串行化執(zhí)行

InnoDB默認(rèn)支持REPEATABLE READ,但與標(biāo)準(zhǔn)SQL不同箫荡,InnoDB在REPEATABLE READ事務(wù)隔離級別下羔挡,使用Next-Key Lock算法,避免了幻讀問題利术。

事務(wù)的實(shí)現(xiàn)

redo log

redo log稱為重做日志印叁,保證事務(wù)的原子性轮蜕,持久性

當(dāng)前事務(wù)數(shù)據(jù)庫系統(tǒng)普遍采用Write Ahred Log策略(WAL跃洛,預(yù)寫式日志)汇竭,即當(dāng)事務(wù)提交時韩玩,先寫重做日志找颓,再修改磁盤頁數(shù)據(jù)。如果宕機(jī)益老,則通過重做日志來完成數(shù)據(jù)的恢復(fù)捺萌。這也是事務(wù)ACID中D(Durability持久性)的要求酷誓。
實(shí)際上是最先操作是修改內(nèi)存池中的頁數(shù)據(jù)盐数。先寫重做日志是相對于修改磁盤數(shù)據(jù)而言玫氢。

任何對Innodb表的更新漾峡,Innodb都會將更新操作轉(zhuǎn)化為redo log并寫入磁盤,redo log中記錄了修改的詳細(xì)信息敬特。

redo log是物理日志,記錄頁的偏移量和字節(jié)等數(shù)據(jù)掰伸。
重做redo log合搅,實(shí)際是重做提交事務(wù)修改的頁物理操作歧蕉。

innodb_flush_log_at_trx_commit參數(shù)控制重做日志緩存刷新到磁盤的策略惯退。
1:默認(rèn)催跪,事務(wù)提交必須調(diào)用一次fsync操作
0:事務(wù)提交時不進(jìn)行寫入重做日志操作荣倾,由master thread每1秒進(jìn)行一次fsync操作
2:事務(wù)提交時僅將重做日志寫入文件系統(tǒng)緩存舌仍,不進(jìn)行fsync操作铸豁,當(dāng)mysql宕機(jī)而操作系統(tǒng)不宕機(jī)時推姻,不會導(dǎo)致事務(wù)丟失藏古。

除了事務(wù)提交時拧晕,刷新重做日志到磁盤還有如下場景

  1. redo log buffer已經(jīng)使用一半內(nèi)存空間

  2. Async/Sync Flush Checkpoint

log block

重做日志緩沖,重做日志文件都是以塊(block)的方法進(jìn)行保存的靡馁,稱為重做日志塊(redo log block)臭墨,每塊的大小為512字節(jié)。重做日志塊與磁盤扇區(qū)大小一樣侠畔,因此重做日志的寫入可以保證原子性红竭,不需要doublewrite技術(shù)德崭。

日志塊由三部分組成眉厨,依次為日志塊頭(log block header)憾股,日志內(nèi)容(log body)服球,日志塊尾log block tailer

日志塊頭內(nèi)容以下

變量 字節(jié) 描述
LOG_BLOCK_HDR_NO 4 log buffer由log block組成,在內(nèi)部log buffer就好似一個由log block數(shù)組粉渠,LOG_BLOCK_HDR_NO用于標(biāo)記這個數(shù)組的下標(biāo),遞增并且循環(huán)使用雕沉。第一位用做flush bit坡椒,最大值為2G
LOG_BLOCK_HDR_DATA_LEN 2 表示log block占用的大小倔叼。最大為0x200,表示log block512字節(jié)
LOG_BLOCK_FIRST_REC_GROUP 2 新事務(wù)第一個日志偏移量肥印。如果log block中存儲了事務(wù)L1后還有空余空間,還會存儲下一個事務(wù)L2的內(nèi)容敷硅,LOG_BLOCK_FIRST_REC_GROUP記錄事務(wù)L2的偏移量绞蹦。

若LOG_BLOCK_FIRST_REC_GROUP與LOG_BLOCK_HDR_DATA_LEN相同,表示當(dāng)前l(fā)og block不含新的日志
LOG_BLOCK_HDR_NO是通過lsn計(jì)算得到的榜旦,因此InnoDB也可以通過lsn定位到具體的redo log幽七。

日志塊尾只有LOG_BLOCK_TRL_NO,4字節(jié)溅呢,與LOG_BLOCK_CHECKPOINT_NO保持一致

log group

重做日志組是一個邏輯概念澡屡,由多個重做日志文件redo log file組成,每個log group中的日志大小是相同的咐旧。默認(rèn)重做日志組由ib_logfile0驶鹉,ib_logfile1組成铣墨。
InnoDB 1.2 版本前,重做日志組的總大小要小于4GB上忍,InnoDB 1.2 版本開始吓笙,提高到512GB

對log block的寫入追加在redo log file的最后部分叁鉴,當(dāng)一個redo log file被寫滿時常侣,會接著寫入下一個redo log file巾乳,使用方式為round-robin压状。
架構(gòu)篇說過莺匠,當(dāng)頁被Checkpoint刷新到磁盤后遥缕,對應(yīng)的重做日志就不需要了 宝穗,其空間可以被覆蓋重用橱鹏。

每個redo group的第一個redo log file中前2kb不保存log block的信息杉辙,而是保存log file header,checkpoint信息。
redo log使用順序?qū)懀俣群芸欤玞heckpoint后叙量,需要更新第一個日志文件的頭部checkpoint標(biāo)記,這時并不是順序?qū)憽?br> redo group非第一個redo log file中前2KB內(nèi)容并不存儲信息笆载,預(yù)留為空雄家。

redo log file前2k內(nèi)容勾效,依次存放以下數(shù)據(jù)

屬性 字節(jié)
LOG FILE HEADER 512
CHECKPOINT BLOCK1 512
512
CHECKPOINT BLOCK2 512

重點(diǎn)看一下CHECKPOINT BLOCK的內(nèi)容

屬性 字節(jié) 解析
LOG_CHECKPOINT_NO 8 單調(diào)遞增的值米死,每次checkpoint操作完成后進(jìn)行自增操作
LOG_CHECKPOINT_LSN 8 checkpoint的值
LOG_CHECKPOINT_OFFSET 4 checkpoint的值對應(yīng)的在重做日志的偏移量

LOG_CHECKPOINT_LSN表示checkpoint的值,LSN小于該值的頁都已經(jīng)被寫入到磁盤隧魄。CHECKPOINT BLOCK有兩個,InnoDB會交替進(jìn)行checkpoint值的更新汇跨。
這樣即使某次checkpoint block寫失敗了,那么崩潰恢復(fù)的時候從上一次記錄的checkpoint開始恢復(fù)朴译,也能正確的恢復(fù)數(shù)據(jù)庫事務(wù)迹辐。

恢復(fù)時嘿悬,InnoDB需要讀取這兩個CHECKPOINT BLOCK,取其中較大的LOG_CHECKPOINT_LSN轮纫,恢復(fù)大于該值的重做日志搓谆。

LSN

LSN 即日志序列號( Log Sequence Number ),它是每個redo log的序號瘤睹。

LSN存在多處渤涌,代表不同含義

1. 代表重做日志寫入總量
LSN是單調(diào)遞增的酌伊,保存在log_sys中(InnoDB運(yùn)行時會維護(hù)一個對象鼻由,負(fù)責(zé)管理 Redo Log Buffer蕉世,啟動時由log_init()函數(shù)負(fù)責(zé)初始化)
每寫入一個redo log時,LSN就會遞增該 Redo Log 寫入的字節(jié)數(shù)昭抒,例如新增一個log長度是len肠鲫,則log_sys->lsn += len。

2. 代表checkpoint最新位置氢哮,見上面的CHECKPOINT BLOCK中的LOG_CHECKPOINT_LSN袋毙。

當(dāng)InnoDB正常shutdown,在flush redo log和臟頁后冗尤,會做一次完全同步的checkpoint听盖,并將checkpoint的LSN寫到共享表空間的FSP HEADER PAGE的FIL_PAGE_FILE_FLUSH_LSN變量中。
(由于已經(jīng)完全checkpoint裂七,下次啟動時皆看,lsn可以被重新賦予常量初始值LOG_START_LSN)

Mysql啟動時,會讀取共享表空間中的FIL_PAGE_FILE_FLUSH_LSN背零,以及CHECKPOINT BLOCK中的較大的LOG_CHECKPOINT_LSN腰吟,如果兩者相同,則說明正常關(guān)閉徙瓶;否則毛雇,就需要進(jìn)行故障恢復(fù)录语。
通過LOG_CHECKPOINT_LSN找到對應(yīng)的redo log,掃描其后的redo log執(zhí)行恢復(fù)操作即可禾乘。

3. 代表頁最后刷新位置澎埠。每個頁的頭部都有一個FIL_PAGE_LSN,記錄該頁最后刷新時LSN的大小始藕,可用于判斷頁是否需要進(jìn)行恢復(fù)操作蒲稳。

參數(shù):innodb_fast_shutdown,控制數(shù)據(jù)庫關(guān)閉操作
0:關(guān)閉時伍派,需要完成所有full purge和merge insert buffer江耀,并將所有臟頁刷新到磁盤
1:默認(rèn)值,只是將臟頁刷新到磁盤
2:只保證日志都寫入到日志文件诉植,下次啟動祥国,會進(jìn)行恢復(fù)操作

參數(shù):innodb_force_recovery,控制數(shù)據(jù)庫恢復(fù)操作
默認(rèn)0晾腔,表示需要恢復(fù)時舌稀,進(jìn)行所有的恢復(fù)操作。
其他配置值不一一列出灼擂。

undo

undo log保證事務(wù)的原子性壁查, 幫助事務(wù)回滾以及MVCC功能。
undo是邏輯日志剔应,對每行數(shù)據(jù)進(jìn)行記錄睡腿,記錄的是每個操作的逆操作。
回滾操作峻贮,實(shí)際做的是先前相反的工作席怪,對于insert,做一個delete纤控,對于delete挂捻,做一個insert,對于update嚼黔,做一個相反的update细层。

undo的存儲

InnoDB將undo log看做數(shù)據(jù),通過Page保存undo log唬涧。

回滾段
回滾段也是一個段對象,保存在頁(0,6)處(共享表空間第6頁)盛撑,內(nèi)容如下

變量 字節(jié) 描述
TRX_RSEG_MAX_SIZE 未使用
TRX_RSEG_HISTORY_SZIE 4 HISTORY鏈表中UNDO頁的數(shù)量
TRX_RSGE_HISTORY 16 已提交的undo日志鏈表碎节,可被purge回收
TRX_RSEG_FSEG_HEADER 10 回滾段的SEGMENT HEADER
TRX_RSEG_UNDO_SLOTS 4*1024 指向UNDO段SEGMENT HEADER所在頁的偏移量

一個UNDO段可以管理一個事務(wù),一個回滾段可以管理1024個UNDO段抵卫。
InnoDB1.1之前狮荔,只有一個回滾段胎撇,支持最大并發(fā)事務(wù)為1026。
InnoDB1.1開始殖氏,最大支持128個回滾段晚树。
位于(0,5)的FIL_PAGE_TYPE_SYS,記錄了所有回滾段所在頁雅采。

UNDO段
UNDO段是真正存儲undo log的地方爵憎。它實(shí)際上是一個UNDO頁鏈表。鏈表第一個UNDO頁由以下部分組成:

  • UNDO LOG PAGE HEADER

  • UNDO LOG SEGMENT HEADER

  • UNDO日志

UNDO LOG PAGE HEADER內(nèi)容如下

變量 字節(jié) 描述
TRX_UNDO_PAGE_TYPE 2 undo日志的類型婚瓜,TRX_UNDO_INSERT或TRX_UNDO_UPDATE
TRX_UNOD_PAGE_STARE 2 UNDO頁最新一個事務(wù)undo日志所在位置
TRX_UNDO_PAGE_FREE 2 UNDO頁空閑的偏移量
TRX_UNDO_PAGE_NODE 12 UNDO頁的鏈表節(jié)點(diǎn)

關(guān)于TRX_UNDO_PAGE_NODE宝鼓,可以參考存儲篇的鏈表結(jié)構(gòu)

UNDO LOG SEGMENT HEADER內(nèi)容如下

變量 字節(jié) 描述
TRX_UNDO_STATE 2 UNDO段的狀態(tài)
TRX_UNDO_LAST_LOG 2 最近一個undo log header在頁中的偏移量位置
TRX_UNDO_FSEG_HEADER 10 UNDO段的segment header
TRX_UNDO_PAGE_LIST 16 UNDO頁的鏈表頭

TRX_UNDO_STATE的有效值有TRX_UNDO_ACTIVE,TRX_UNDO_CACHEd,TRX_UNDO_TO_FREE,TRX_UNDO_TO_PURGE。

UNDO LOG SEGMENT HEADER僅保存在UNDO頁鏈表的第一個UNDO頁中巴刻,其他UNDO頁中對應(yīng)位置保留為空

undo記錄結(jié)構(gòu)
每個undo記錄由兩部分組成

  • UNDO LOG HEADER

  • UNDO LOG RECORD

undo log record有update undo log record和insert undo log record兩種類型愚铡,通常insert操作產(chǎn)生insert undo log record,其他DML操作產(chǎn)生update undo log record胡陪。
通過TRX_UNDO_PAGE_TYPE可以看出沥寥,一個UNDO段只能存儲一種類型的undo,insert undo log或update undo log柠座。如果一個事務(wù)同時有INSERT营曼,UPDATE操作,則需要每種類型分配單獨(dú)的UNDO段愚隧,這樣也會導(dǎo)致InnoDB支持最大并發(fā)事務(wù)數(shù)下降蒂阱。

UNDO LOG HEADER內(nèi)容如下

變量 字節(jié) 描述
TRX_UNDO_TRX_ID 8 產(chǎn)生undo日志的事務(wù)id
TRX_UNDO_TRX_NO 8 標(biāo)識事務(wù)提交順序的序號
TRX_UNDO_DEL_MARKS 2 標(biāo)記本組 undo 日志中是否包含delete mark 產(chǎn)生的 undo 日志
TRX_UNDO_LOG_START 2 表示本組 undo 日志中第一條 undo 日志的在頁面中的偏移量
TRX_UNDO_DICT_OPERATION 2 是否為DDL操作
TRX_UNDO_TABLE_ID 8 若是DDL操作,操作表的id
TRX_UNDO_NEXT_LOG 2 下一個UNDO LOG HEADER位置
TRX_UNDO_PREV_LOG 2 上一個UNDO LOG HEADER位置
TRX_UNDO_HISTORY_NODE 12 HISTORY鏈表節(jié)點(diǎn)

由于purge可能移除一些undo log record狂塘,TRX_UNDO_LOG_START不一定等于UNDO LOG HEADER結(jié)束位置偏移量录煤。

事務(wù)開啟時,會分配一個唯一的嚴(yán)格遞增的事務(wù)ID以及UNDO段荞胡,并設(shè)置其TRX_UNDO_STATE變量為TRX_UNDO_ACTIVE妈踊。

注意:
InnoDB將undo log看做數(shù)據(jù),UNDO頁與普通的數(shù)據(jù)頁一起管理泪漂,會依據(jù)LRU規(guī)則刷新出內(nèi)存廊营,后續(xù)再從磁盤讀取。
同樣萝勤,對undo log的操作也需要記錄到redo log中露筒。
如對于一個insert操作,redo log不僅要記錄insert操作敌卓,還需要記錄一個生成undo insert的操作慎式。

進(jìn)行恢復(fù)時,InnoDB會重做所有事務(wù),包括未提交的事務(wù)和回滾了的事務(wù)瘪吏。然后通過undo log回滾那些未提交的事務(wù)癣防。

參數(shù):
innodb_undo_directory:指定UNDO獨(dú)立表空間位置
innodb_undo_logs:設(shè)置rollback segment個數(shù),默認(rèn)為128(一個rollback segment支持1024并發(fā))掌眠,在InnoDB 1.2蕾盯,該參數(shù)替換之前版本的innodb_rollback_segments
innodb_undo_tablespaces:組成undo表空間文件個數(shù)
innodb_undo_log_truncate: MySQL 自動收縮 Undo 表空間,防止磁盤占用過大蓝丙,默認(rèn)開啟(Mysql5.7.5之后提供)
innodb_max_undo_log_size:超過該閥值將被自動收縮

UNDO頁復(fù)用
當(dāng)事務(wù)提交時级遭,需要處理UNDO頁:

  • 如果當(dāng)前的undo log只占一個page,且占用的header page大小使用不足其3/4時(TRX_UNDO_PAGE_REUSE_LIMIT)迅腔,則狀態(tài)設(shè)置為TRX_UNDO_CACHED装畅,表示該UNDO頁可以復(fù)用,之后新的undo log記錄在當(dāng)前undo log的后面沧烈。

  • 如果是Insert_undo(undo類型為TRX_UNDO_INSERT)掠兄,則狀態(tài)設(shè)置為TRX_UNDO_TO_FREE,該undo log可被刪除

  • 如上不滿足锌雀,則表明該undo log可能需要Purge線程去執(zhí)行清理操作蚂夕,狀態(tài)設(shè)置為TRX_UNDO_TO_PURGE,將undo log加入到回滾段的TRX_RSGE_HISTORY中腋逆,由purge回收婿牍。

purge操作

purge用于最終完成delete和update操作,這樣設(shè)計(jì)是因?yàn)镮nnoDB支持MVCC惩歉,所以記錄不能在事務(wù)提交時立即進(jìn)行處理等脂,其他事務(wù)可能正在引用這行數(shù)據(jù)。
(delete操作將記錄的delete flag設(shè)置為1)

前面說過撑蚌,回滾段TRX_RSGE_HISTORY列表上遥,會根據(jù)事務(wù)提交的順序,將undo log鏈接起來争涌。

執(zhí)行purge過程中粉楚,InnoDB從TRX_RSGE_HISTORY列表中找到第一個需要被清理的記錄trx1,清理后InnoDB會在trx1所在undo log頁繼續(xù)查找是否存在可以被清理的記錄亮垫,直到該UNDO頁沒有可以清理的記錄模软,再回到history list中查找下一個需要被清理的記錄。
由于可以重用饮潦,一個undo log可能存放了不同事務(wù)的undo log燃异。因此purge操作需要涉及磁盤的離散讀取操作,是一個比較緩慢的過程害晦。

MVCC原理

隱藏列
存儲篇說過特铝,行數(shù)據(jù)中有兩個隱藏列用于實(shí)現(xiàn)MVCC
TransactionID:DB_TRX_ID暑中,記錄操作該數(shù)據(jù)事務(wù)的事務(wù)ID
RollPointer:DB_ROLL_PTR壹瘟,指向上一個版本數(shù)據(jù)在undo log 里的位置指針

事務(wù)修改行數(shù)據(jù)時鲫剿,會將修改前的數(shù)據(jù)放入undo log中,并修改TransactionID為當(dāng)前事務(wù)ID稻轨,RollPointer指向上一個版本數(shù)據(jù)位置灵莲。
例如將行數(shù)據(jù)的一個字段從A -> B -> C,TransactionID殴俱,RollPointer變化如下

注意:這里通過RollPointer組織成一條undo log鏈政冻。

快照
在RR級別下,事務(wù)在begin/start transaction之后的第一條select讀操作后, 會創(chuàng)建一個快照(read view)线欲,將當(dāng)前系統(tǒng)中活躍的其他事務(wù)記錄記錄起來明场。
在RC級別下,事務(wù)中每條select語句都會創(chuàng)建一個快照李丰。

可見性判斷
設(shè)要讀取的行的最后提交事務(wù)id為 trx_id_current苦锨,
當(dāng)前事務(wù)創(chuàng)建的快照read view 中最早的事務(wù)id為up_limit_id, 最遲的事務(wù)id為low_limit_id

1. trx_id_current < up_limit_id, 當(dāng)前事務(wù)在讀取該行記錄時, 該行記錄的最新事務(wù)ID是小于當(dāng)前系統(tǒng)所有活躍的事務(wù),所以當(dāng)前行數(shù)據(jù)可見趴泌。

2. trx_id_current > low_limit_id, 當(dāng)前事務(wù)開啟后舟舒,該行記錄被修改并提交,數(shù)據(jù)不可見嗜憔。

3. up_limit_id <= trx_id_current <= low_limit_id秃励,該行記錄最新事務(wù)處于活動狀態(tài),
這時需要判斷 trx_id_current 在不在 快照的活躍事務(wù)ID列表中吉捶。
若不在夺鲜,數(shù)據(jù)可見。若在呐舔,不可見币励,需要查找undo log 鏈得到上一個版本再進(jìn)行可見性判斷。

group commit

對于InnoDB滋早,事務(wù)提交進(jìn)行兩個操作:

  1. 修改內(nèi)存中事務(wù)對應(yīng)的信息榄审,并將日志寫入重做日志緩沖

  2. 調(diào)用fsync將重做日志緩沖寫入磁盤
    group commit,組提交杆麸,即將多個事務(wù)的重做日志緩沖通過一次fsync刷新到磁盤

開啟binlog后搁进,為了保證存儲引擎中的事務(wù)和binlog的一致性,InnoDB使用兩階段事務(wù)昔头。
注意:重做日志是innodb產(chǎn)生饼问,物理格式日志,記錄對每個頁的修改揭斧,在事務(wù)進(jìn)行中不斷寫入莱革。
而binlog是mysql上層產(chǎn)生的峻堰,是一種邏輯日志,在事務(wù)提交完成時一次寫入盅视。

兩階段事務(wù)步驟如下
Prepare 階段:SQL 已經(jīng)成功執(zhí)行并生成 redo 和 undo 的內(nèi)存日志捐名;InnoDB 將回滾段設(shè)置為 prepare 狀態(tài);
binlog提交階段:binlog 內(nèi)存日志數(shù)據(jù)寫入文件系統(tǒng)緩存并通過fsync() 寫入磁盤闹击;
Commit 階段:fsync() 將 binlog 文件系統(tǒng)緩存日志數(shù)據(jù)永久寫入磁盤镶蹋;

恢復(fù)操作
在 prepare 階段前崩潰,該事務(wù)直接回滾赏半;
在 binlog 已經(jīng) fsync() 贺归,但 InnoDB 未 commit 時崩潰;恢復(fù)時断箫,將會從 binlog 中獲取事務(wù)信息拂酣,重做該事務(wù)并提交,使 InnoDB 和 binlog 始終保持一致婶熬。

InnoDB需要保證 binlog 的寫入順序和 InnoDB 事務(wù)提交順序一致。

我們使用on-line backup下來的備份文件進(jìn)行恢復(fù)或者主備同步尸诽,因?yàn)镮nnoDB檢測最新的事務(wù)T3已經(jīng)Commit盯另,不需要進(jìn)行恢復(fù)性含,結(jié)果導(dǎo)致事務(wù)T1數(shù)據(jù)丟失。

InnoDB1.2版本前 鸳惯,使用 prepare_commit_mutex 保證順序商蕴,只有當(dāng)上一個事務(wù) commit 后釋放鎖,下個事務(wù)才可以進(jìn)行 prepare 操作芝发。但導(dǎo)致開啟二進(jìn)制日志后绪商,group commit功能失效,性能較差辅鲸。

InnoDB1.2版本后進(jìn)行了優(yōu)化格郁,
prepare 階段不變,
binlog提交階段和commit 階段拆分為三個過程独悴,每個階段都會去維護(hù)一個隊(duì)列例书,第一個進(jìn)入該隊(duì)列的作為 leader 線程,其他作為 follower 線程刻炒;leader 線程會收集 follower 的事務(wù)决采,并負(fù)責(zé)做 sync,follower 線程等待 leader 通知操作完成坟奥。

  • Flush階段树瞭,將隊(duì)列中每個事務(wù)的binlog都寫入內(nèi)存

  • Sync階段拇厢,將內(nèi)存隊(duì)列中的binlog刷新到磁盤,若隊(duì)列中有多個事務(wù)晒喷,僅一次fsync操作就完成日志的寫入孝偎。
    Commit階段,leader根據(jù)隊(duì)列順序調(diào)用InnoDB事務(wù)的提交厨埋,這時就可以使用group commit功能邪媳。
    由于三個階段都是根據(jù)隊(duì)列順序執(zhí)行操作捐顷,所以保證 binlog 的寫入順序和 InnoDB 事務(wù)提交順序一致荡陷。

當(dāng)有一組事物在進(jìn)行Commit階段時,其他新事物可以進(jìn)行Flush階段迅涮,從而使用group commit不斷生效废赞。

轉(zhuǎn)載自:

深入理解InnoDB -- 事務(wù)篇

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叮姑,隨后出現(xiàn)的幾起案子唉地,更是在濱河造成了極大的恐慌,老刑警劉巖传透,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耘沼,死亡現(xiàn)場離奇詭異,居然都是意外死亡群嗤,警方通過查閱死者的電腦和手機(jī)狂秘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門者春,熙熙樓的掌柜王于貴愁眉苦臉地迎上來清女,“玉大人嫡丙,你說我怎么就攤上這事〉狙铮” “怎么了泰佳?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長浇坐。 經(jīng)常有香客問我近刘,道長觉渴,這世上最難降的妖魔是什么徽惋? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任险绘,我火速辦了婚禮宦棺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹈丸。我一直安慰自己白华,他們只是感情好弧腥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布管搪。 她就那樣靜靜地躺著更鲁,像睡著了一般澡为。 火紅的嫁衣襯著肌膚如雪景埃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天驯绎,我揣著相機(jī)與錄音剩失,去河邊找鬼册着。 笑死指蚜,一個胖子當(dāng)著我的面吹牛摊鸡,可吹牛的內(nèi)容都是我干的免猾。 我是一名探鬼主播猎提,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼旁蔼,長吁一口氣:“原來是場噩夢啊……” “哼棺聊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葵诈,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晕城,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰锁,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡槽奕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年粤攒,在試婚紗的時候發(fā)現(xiàn)自己被綠了夯接。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盔几。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡逊拍,死狀恐怖芯丧,靈堂內(nèi)的尸體忽然破棺而出缨恒,到底是詐尸還是另有隱情骗露,我是刑警寧澤萧锉,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布驹暑,位于F島的核電站优俘,受9級特大地震影響掀序,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜财饥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望满着。 院中可真熱鬧宁改,春花似錦还蹲、人聲如沸谜喊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炫狱。三九已至视译,卻和暖如春酷含,著一層夾襖步出監(jiān)牢的瞬間椅亚,已是汗流浹背呀舔。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工霜瘪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颖对,地道東北人缤底。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓琳拭,卻偏偏與公主長得像训堆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子白嘁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容