《Mysql技術內幕,Innodb存儲引擎》——事物
事物
- 事物中的操做要麼都成功要麼都不作,這是事物的目的,也是事物模型與文件系統的重要特徵之一。
- 扁平事物(Flat Transactions) 全部操做都處於同一層次,要麼都作要麼都執行要麼都回滾,沒法提交或回滾一部分。由於其模型簡單而普遍使用。
- 帶保存點的扁平事物(Flat Transaction with Savepoint) 與扁平事物相比其容許在執行過程當中回滾到某一個較早的狀態(savepoint),保存點 用來記住事物當前的狀態。保存點在事物內部是遞增的,即便回滾事後。
- 鏈事物(Chained Transaction) 提交一個事物時,釋放不須要的對象,將必要的對象隱式地傳給下一個要開始的事物。也就是說提交事物和開始下一個事物合併成了一個原子操做。其回滾僅限於當前事物。
- 嵌套事物(Nested Transaction) 層次嵌套事物,能夠當作一顆事務樹。葉子節點是扁平事物,子事物既能夠提交也能夠回滾,樹中任意一個事物的回滾將引發其全部子事物的回滾,所以子事物只保留了ACI而不具備D的特性。
- 分佈式事物(Distributed Transaction) 分佈式環境下運行的扁平事物。
事物的實現
redo
1. 基本概念mysql
- 重作日誌用於實現持久性,由redo log buffer和redo log file兩部分組成。
- Innodb在commit時必須先將事物的全部redo log寫入到redo log file進行持久化。
- 爲了確保redo log的持久性,在每次將重作日誌緩衝寫入日誌文件後將調用一次fsync(緣由在於寫入日誌文件不少時候只是寫入文件系統的緩存,調用fsync則直接寫入了磁盤)。
- 爲了提升commit的性能,也能夠設置等待一個時間週期後再執行fsync,但極可能致使數據丟失。
- redo log是屬於存儲引擎層的日誌,記錄每一個頁的修改。而二進制日誌則是數據庫層的日誌記錄的是操做對應的SQL語句。
2. 日誌結構sql
- redo log以512B的塊(block)進行存儲,稱爲重作日誌塊(redo log block)。
- 因爲512B與磁盤扇區同樣大,所以能夠保證其寫入的原子性,因此不須要double write來保證數據一致性。
- log block中包括lob block header、log block 和log block tailer三部分。
- log group(重作日誌組)其中有多個重作日誌文件,每一個文件大小相同。
- 重作日誌文件中存儲的就是log buffer中保存的log block,所以物理存儲也是以block管理。
- log buffer刷到文件規則:事物提交、log buffer中有一半的內存已經被使用和log checkpoint。
- 每一個redo log file的前2KB不寫入block,由於log group中第一個文件將寫入一些信息。
3. LSN數據庫
- Log Sequence Number,日誌序列號,遞增。
- LSN表示重作日誌寫入的字節總量,checkpoint的位置,頁數據的版本(Innodb檢測是否須要恢復就是根據頁的LSN與redo log中LSN對比)。
- innodb重啓時都會嘗試着恢復數據,恢復時只須要回復checkpoint開始的日誌部分。
undo
1. 基本概念緩存
- undo log是爲事物回滾準備的,MVCC也依賴於undo log。
- undo存放在undo段中,undo段位於共享表空間。
- undo是邏輯日誌,只是將數據庫邏輯地恢復到事物前的樣子,所以回滾後可能數據結構和頁自己都不同了。
2. 存儲管理數據結構
- Innodb中有rollback segment,每一個回滾段中記錄1024個undo log segment,在undo log segment中進行undo頁的申請。
- innodb 1.1以前只有一個rollback segment,1.1後支持最大128個,所以同時支持事物的限制爲128*1024.
- 事物在寫入undo log時一樣會寫入redo log(undo也是寫入數據到頁中)。
- 事物提交後不能立刻刪除undo log,由於可能MVCC在使用,所以將其放入一個鏈表中,刪除與否由purge線程判斷。
- undo log放入鏈表後,若是該頁的使用空間小於3/4,則表示該頁還能夠被重用。
- undo log的列表是以記錄的進行組織的,而undo log中存放不一樣事物的undo log,所以purge在回收時涉及磁盤的離散讀取操做。
- insert undo log事物提交後能夠直接刪除。
- update undo log是對delete和update操做產生的undo log,須要支持MVCC所以不能夠直接刪除,須要purge線程判斷。
pruge
- delete和update操做通常不直接刪除原數據而是在彙集索引上標記該記錄的delete flag。==(只在彙集索引上標記,若是查詢的數據能夠經過覆蓋索引獲取那麼不就能查詢出已刪除的數據?)==
- innodb中有個history列表,它根據事物提交的順序將undo log連接起來,先提交的事物總在尾端。
- purge先從history中找到第一個須要被清理的記錄,清理後將對該undo log頁所在的其餘事物進行清理,若是還被別的事物佔用則跳過。該頁清理完成則繼續從history中找下一個。
innodb_purge_batch_size
設置每次purge清理的undo頁數,若是值太大則會致使CPU和磁盤IO過於集中。
- 當history list長度達到限制後,其會延緩DML操做。
group commit
- group commit指一次fsync能夠刷新確保多個事物日誌被寫入文件。
- 開啓二進制日誌後,爲了保證存儲引擎層中的事物和二進制日誌的一致性,兩者之間使用兩階段事物。
- 事物提交時Innodb進行prepare操做。
- mysql數據庫上層寫入二進制日誌。
- Innodb將日誌寫入redo log file,先修改內存中事物對應的信息並將其寫入日誌緩衝,然後調用fsync。
- 爲了保證二進制日誌與Innodb事物提交順序一致,使用
prepare_commit_mutex
鎖,這將致使group commit失效。
- 爲了支持group commit Mysql5.6使用Binary Log Group Commit(BLGC)。
- 在Mysql數據庫的上層進行提交時先按照順序將其放入一個隊列,第一個事物成爲leader其他爲follower,步驟以下:
- Flush階段,將每一個事物的二進制日誌寫入內存中。
- Sync階段,將內存中二進制日誌刷到磁盤,若隊列含有多個事物則僅一次fsync完成日誌刷入
- Commit階段,leader根據順序調用存儲引擎層的事物提交。
分佈式事物
- Innodb支持XA事物,在使用分佈式事物時須要使用Serializable的隔離級別。使用兩階段提交。
- XA事物由資源管理器(Resource Managers)、事物管理器(Transaction Manager)和應用程序(Application Program)組成。
歡迎關注本站公眾號,獲取更多信息