目錄
redo(重做日志):
特點:
組成:
整體流程:
redo log buffer與redo log file之間的刷盤策略:
異步刷盤:
同步刷盤:
拆中策略:
undo(回滾日志):
存儲結構:
undo頁的重用:
回滾段與事務:
回滾段中的數據分類:
未提交的回滾數據:
已經提交但未過期的回滾數據:
事務已經提交并過期的數據:
生成過程:
類型分類:
insert undo log:
update undo log:
undo刪除:
insert undo log:
update undo log:
總結:
事務的隔離由鎖機制實現,而事務的原子性、一致性和持久性是由事務的redo日志和undo日志來保證。其中redo是指重做日志,是存儲引擎生成的日志,記錄的是“物理級別”上的頁修改操作,提供再寫入操作,回復提交事務修改的頁操作,用于保證事務的持久性。undo日志是指回滾日志,是存儲引擎層生成的日志,記錄的是邏輯操作日志,回滾行記錄到某個特定的版本,用于保證事務的原子性、一致性。
redo(重做日志):
InnoDB存儲引擎是以頁為單位來管理存儲空間的,在訪問頁面之前,需要把磁盤上的頁緩存到內存中的緩沖池里面才可以訪問。所有的變更都必須先更新緩沖池中的數據,然后緩沖池中的臟頁(內存中修改了而磁盤中還未修改的數據頁)會一定的頻率被刷入磁盤,通過緩沖池來優化CPU和磁盤之間的交互。
InnoDB存儲引擎的事務采用了WAL技術,WAL技術的思想是先寫日志,再寫磁盤,只有當日志寫入成功,才算事務提交成功,而這里的日志指的是redo日志。當事務提交成功之后,還沒有進行刷盤時,發生了宕機,就可以通過redo日志來進行恢復數據。
優點是:降低了刷盤的頻率(不用去維持實時刷新磁盤),占用的空間非常小(存儲表空間id,頁號,偏移量以及需要更新的值,所以存儲空間很小,而且刷盤速度快)。
特點:
redo日志是順序寫入磁盤的,在執行事務的過程中,每執行一條語句,就可能產生若干條redo日志,這些日志是按照產生的順序寫入磁盤的,使用順序IO,效率比隨機IO快。
事務執行過程中,redo不斷記錄,在事務執行過程中,是一直不斷地往redo順序記錄,直到事務提交。
組成:
重做日志的緩沖(redo log buffer),保存在內存中,是易丟失。服務器啟動時就向操作系統申請了一大片重做日志的緩沖的連續內存空間,也就是redo日志緩沖區,這片內存空間被分成很多連續的redo log block,一個占用512字節。
重做日志文件(redo log file),保存在硬盤中,是持久的。
整體流程:
先將原數據從磁盤中讀入內存中,修改數據的內存拷貝。
生成一條重做日志并寫入redo log buffer,記錄的是數據被修改后的值。
當事務提交時,將redo log buffer中的內存刷新到redo log file,對redo log file采用追加寫的方式。
定期將內存中修改的數據刷新到磁盤中。
redo log buffer與redo log file之間的刷盤策略:
重做日志緩沖刷盤到重做日志文件不是真正的刷到磁盤中去,只是刷入到文件系統緩存中,真正的寫入由系統決定。而此時InnoDB就存在一個問題,如果系統宕機了,那么數據也會丟失。
所以針對這種情況,給出了一個innodb_flush_log_at_trx_commit參數來控制commit提交事務時,如何將重做日志緩沖中的日志刷新到重做日志文件中。
異步刷盤:
1.當innodb_flush_log_at_trx_commit=0時,表示每次事務提交時不進行刷盤操作。
InnoDB中有一個后臺線程,每隔1秒,會把重做日志緩沖中的內容寫道文件系統緩存中,然后調用刷盤操作。如果崩潰的話,可能會丟失1秒內的已提交事務數據。事務提交之后,不需要等待刷盤。
當一個沒有提交事務的重做日志記錄,也可能會刷盤。因為在事務執行過程中重做日志記錄會寫入到重做日志緩沖中,而這些記錄會被后臺線程刷盤。
當重做日志緩沖占用的空間即將達到innodb_log_buffer_size的一半時,后臺線程會主動刷盤。
如果事務最終未提交或者崩潰恢復時,會通過undo日志回滾已刷盤的的未提交數據,保證數據的原子性。
同步刷盤:
2.當innodb_flush_log_at_trx_commit=1時,表示每次事務提交時都將進行同步刷盤操作。(默認值)
只要事務提交成功,重做日志記錄一定在硬盤中,不會有任何數據丟失。如果事務執行期間宕機,相對應的部分日志丟失,但是事務并沒有提交,所以日志丟失也不會造成損失,可以保證持久性,數據不會丟失,但是效率最差,因為事務提交之后需要等待重做日志緩沖中的內容寫入到文件系統緩存中同時還要進行刷盤。
拆中策略:
3.當innodb_flush_log_at_trx_commit=2時,表示每次事務提交時都只把重做日志緩沖內容寫入到文件系統緩存中,不進行同步。由操作系統決定同步到磁盤文件中的時間。后臺線程以一定的時間間隔進行一次將文件系統緩存中的內容寫入到磁盤中。事務提交之后,需要將重做日志緩存中的內容寫入到文件系統緩存中,不需要等待刷盤。性能介于異步刷盤和同步刷盤之間。
如果操作系統宕機,文件系統緩存可能會有數據丟失,就無法滿足持久性。
undo(回滾日志):
在事務更新數據的前置操作要先寫入一個回滾日志。
undo是邏輯日志,只是將數據庫邏輯地恢復到原來的樣子,但是數據結構和頁本身在回滾之后可能不相同。
回滾日志也會產生重做日志,因為回滾日志也需要持久性的保護。
存儲結構:
InnoDB對undo的管理采用段的方式,也就是回滾段,每個回滾段記錄1024個undo log segment,在每個undo log segment段中進行undo頁的申請。
undo頁的重用:
當開啟一個事務需要寫undo日志時,就得去undo log segment中找空閑的位置,當有空閑位置時,就去申請undo頁,這樣的話,每開啟一個事務就申請一個頁,很浪費存儲空間。所以可以對undo頁進行判斷是否可以重用。
當事務提交時,并不會立刻刪除undo頁,因為undo頁的重用一個undo頁可能混雜著其他事務的undo log。undo log在事務提交后,會被放到一個鏈表中,然后判斷undo頁的使用空間是否小于3/4,如果小于,則表示當前的undo頁可以被重用,就不會被回收,其他事務的undo log可以記錄在當前的undo頁后面,由于undo頁是離散的,所以清理對應的磁盤空間時,效率不高。
回滾段與事務:
每個事務只會使用一個回滾段,一個回滾段在同一時刻可能會服務多個事務。
當一個事務開始時,會制定一個回滾段,在事務進行的過程中,數據被修改時,原始的數據會被覆蓋到回滾段中。
在回滾段中,事務會不斷填充盤區,直到事務結束或者空間被用完。如果當前盤區不夠用,那么事務會在段中請求擴展到下一個盤區,如果已分配的盤區都用完,事務會覆蓋最初的盤區或者在回滾段允許的情況下擴展新的盤區來使用。
回滾段存在于undo表空間中,在數據庫中可以存在多個undo表空間,但同一時刻只能使用一個undo表空間。
當事務提交時,InnoDB存儲引擎會將undo log放到列表中,以方便之后的清除操作,還會判斷undo log所在的頁是否可以重用,若可以則分配給下一個事務使用。
回滾段中的數據分類:
未提交的回滾數據:
該數據所關聯的事務未提交,用于實現讀一致性,所以該數據不能被其他事務的數據覆蓋。對應事務的活動狀態或者部分提交狀態。
已經提交但未過期的回滾數據:
該數據關聯的事務已經提交,但是仍受到undo retention參數的保持時間的影響。也就是事務提交之后,undo日志未被清理線程清理,主要針對的是update undo log。
事務已經提交并過期的數據:
該數據關聯的事務已經提交,而且數據保存時間已經超過undo retention參數指定的時間,屬于已經過期的數據。也就是事務提交之后,undo日志不再被MVCC依賴,清理線程通過掃描鏈表清理了過期條目。當回滾段滿了之后,會優先覆蓋“事務已經提交并過期的數據”。
事務提交之后不能馬上刪除undo log以及undo log所在的頁,因為可能還有在其他事務需要通過undo log來得到行之前的版本,事務提交時,會將undo log放入一個鏈表中。
生成過程:
InnoDB存儲引擎中有幾個隱藏的列:
DB_ROW_ID:如果沒有主鍵且沒有唯一索引,那么會自動添加一個隱藏列作為主鍵。
DB_TRX_ID:每個事務都會分配一個事務ID,當對某條記錄進行變更時,就會將這個事務ID寫入trx_id中。
DB_ROLL_PTR:回滾指針,指向undo log的指針。
當插入一條數據時,會生成一條undo log,記錄著undo log的序號、插入主鍵的列和值等信息,在進行回滾時,直接通過主鍵把對應的數據刪除即可。
更新操作會分更新主鍵和不更新主鍵的情況,
如果是不更新主鍵,就把此次更新之前的數據寫入到新的undo log中,讓回滾指針指向新的undo log,讓新的undo log指向舊的undo log,可以參考鏈表的頭插法。
如果是更新主鍵的操作,那么會把邏輯刪除的標識從0置為1,這個改變也需要通過一個undo log進行記錄頭插到該記錄的回滾指針后面,然后在此條記錄后面插入一條新的記錄且新的記錄的回滾指針指向的是主鍵更新前的記錄,新的記錄會產生undo log且undo log序號會遞增。
類型分類:
insert undo log:
僅處理insert操作新增的數據,用于事務回滾時刪除新插入的數據。回滾時根據主鍵直接刪除對應行。
update undo log:
記錄update和delete操作修改前的數據狀態,支持回滾與快照讀。update:保存被修改字段的舊值,delete:存儲整行數據的原始內容。
undo刪除:
insert undo log:
因為insert操作記錄,只對本事務可見,所以可以在事務提交后進行刪除。
update undo log:
該undo log可能需要提供MVCC機制,因此不能在事務提交時,就進行刪除,需要放到鏈表當中,等待清理線程進行最后的刪除。
總結:
目標數據如果不在緩存池中,將磁盤中的數據頁寫入到內存緩沖池中,將原數據寫入到undo日志中便于回滾,進行數據的更新操作,會將對應的數據寫入到redo日志緩存當中,當提交事務時,根據設定的刷盤策略來進行刷盤,將內存中的臟頁刷到磁盤當中。如果未提交或者事務崩潰,那么則根據undo日志進行一個數據回滾,恢復至原數據,保證數據的可靠性。