這篇文章帶給大家的內容是關於MySQL事務中的redo與undo的分析(圖文),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
我們都知道事務有4種特性:原子性、一致性、隔離性和持久性,在事務中的操作,要麼全部執行,要麼全部不做,這就是事務的目的。事務的隔離性由鎖定機制實現,原子性、一致性和持久性由事務的redo 日誌和undo 日誌來保證。所以這篇文章將討論關於事務中的redo和undo的幾個問題:
redo 日誌與undo日誌分別是什麼?
redo 如何保證交易的持久性?
undo log 是否是redo log的逆過程?
redo log
#Redo 的型別
重做日誌(redo log)用來保證事務的持久性,即事務ACID中的D。實際上它可以分成以下兩種類型:
物理Redo日誌
#邏輯Redo日誌
在InnoDB儲存引擎中,大部分情況下Redo是實體日誌,記錄的是資料頁的物理變化。而邏輯Redo日誌,不是記錄頁面的實際修改,而是記錄修改頁面的一類操作,例如新建資料頁時,需要記錄邏輯日誌。關於邏輯Redo日誌涉及更底層的內容,這裡我們只需要記住絕大數情況下,Redo是實體日誌即可,DML對頁的修改操作,均需要記錄Redo.
Redo log的主要作用是用於資料庫的崩潰復原
Redo log可以簡單分成以下兩個部分:
一是記憶體中重做日誌緩衝(redo log buffer),是易失的,在記憶體中
二是重做日誌檔(redo log file ),是持久的,保存在磁碟中
上面那張圖簡單地體現了Redo的寫入流程,這裡再細說下寫入Redo的時機:
在資料頁修改完成之後,在髒頁刷出磁碟之前,寫入redo日誌。注意的是先修改數據,後寫日誌
redo日誌比數據頁先寫回磁碟
聚集索引、二級索引、undo頁面的修改,均需記錄Redo日誌。
下面以更新交易為例,在宏觀上掌握redo log 流轉過程,如下圖所示:
第一步:先將原始資料從磁碟中讀入記憶體中來,修改資料的記憶體拷貝
#第二步:產生一條重做日誌並寫入redo log buffer,記錄的是資料被修改後的值
第三步:當交易commit時,將redo log buffer中的內容刷新到redo log file,對redo log file採用追加寫的方式
第四步:定期將記憶體中修改的資料刷新到磁碟中
InnoDB是交易的儲存引擎,其透過Force Log at Commit 機制實現交易的持久性,即當交易提交時,先將redo log buffer 寫入到redo log file 進行持久化,待交易的commit作業完成時才算完成。這種做法也稱為 Write-Ahead Log(預先日誌持久化),在持久化一個資料頁之前,先將記憶體中對應的日誌頁持久化。
為了確保每次日誌都寫入redo log file,在每次將redo buffer寫入redo log file之後,預設情況下,InnoDB儲存引擎都需要呼叫一次fsync操作 ,因為重做日誌開啟並沒有O_DIRECT選項,所以重做日誌先寫入到檔案系統快取。為了確保重做日誌寫入到磁碟,必須進行一次 fsync操作。 fsync是一種系統呼叫操作,其fsync的效率取決於磁碟的效能,因此磁碟的效能也影響了交易提交的效能,也就是資料庫的效能。
(O_DIRECT選項是在Linux系統中的選項,使用該選項後,對檔案進行直接IO操作,不經過檔案系統緩存,直接寫入磁碟)
Force Log at Commit機制就是靠InnoDB儲存引擎提供的參數innodb_flush_log_at_trx_commit來控制的,該參數可以控制redo log刷新到磁碟的策略,設定該參數值也可以允許使用者設定非持久性的情況發生,具體如下:
fsync 操作,最安全的配置,保障持久性
當設定參數為2時,則在交易提交時只做write 操作,只保證將redo log buffer寫到系統的頁面快取中,不進行fsync操作,因此如果MySQL資料庫宕機時不會遺失事務,但作業系統宕機則可能遺失事務
當設定參數為0時,表示交易提交時不進行寫入redo log操作,這個操作僅在master thread 完成,而在master thread每1秒進行一次重做日誌的fsync操作,因此實例crash 最多遺失1秒鐘內的交易。 (master thread是負責將緩衝池中的資料非同步刷新到磁碟,保證資料的一致性)
#fsync
和write
操作其實是系統呼叫函數,在許多持久化場景都有使用到,例如Redis 的AOF持久化中也使用到兩個函數。 fsync
操作將資料提交到硬碟中,強制硬碟同步,將一直阻塞到寫入硬碟完成後返回,大量進行fsync
操作就有效能瓶頸,而write
操作將資料寫到系統的頁面快取後立即返回,後面依靠系統的調度機制將快取資料刷到磁碟中去,其順序是user buffer——> page cache——>disk。
除了上面談到的Force Log at Commit機制保證交易的持久性,實際上重做日誌的實作還要依賴於mini-transaction。
Redo的實作實際上跟mini-transaction緊密相關,mini-transaction是一種InnoDB內部使用的機制,透過mini-transaction來保證並發事務操作下以及資料庫異常時資料頁中數據的一致性,但它不屬於事務。
為了使得mini-transaction保證資料頁資料的一致性,mini-transaction必須遵循以下三種協定:
The FIX Rules
Write-Ahead Log
#Force-log-at-commit
## The FIX Rules
修改一個資料頁時需要取得該頁的x-latch(排他鎖),取得一個資料頁時需要該頁的s-latch(讀鎖定或稱為共用鎖) 或是x-latch,持有該頁的鎖直到修改或存取該頁的操作完成。Write-Ahead Log
在前面闡述中就提到了Write-Ahead Log(預先寫日誌)。在持久化一個資料頁之前,必須先將記憶體中對應的日誌頁持久化。每個頁都有一個LSN(log sequence number),代表日誌序號,(LSN佔用8字節,單調遞增), 當一個資料頁需要寫入到持久化設備之前,要求記憶體中小於該頁LSN的日誌先寫入持久化設備那為什麼必須先寫日誌呢?可不可以不寫日誌,直接將資料寫入磁碟?原則上是可以的,只不過會產生一些問題,資料修改會產生隨機IO,但日誌是順序IO,append方式順序寫,是一種串列的方式,這樣才能充分利用磁碟的效能。Force-log-at-commit
這一點也就是前文提到的如何保證事務的持久性的內容,這裡再次總結一下,與上面的內容相呼應。在一個交易中可以修改多個頁,Write-Ahead Log 可以保證單一資料頁的一致性,但無法保證交易的持久性,Force-log-at-commit 要求當一個交易提交時,其產生所有的mini -transaction 日誌必須刷新到磁碟中,若日誌刷新完成後,在緩衝池中的頁刷新到持久化儲存裝置前資料庫發生了宕機,那麼資料庫重新啟動時,可以透過日誌來保證資料的完整性。重做日誌的寫入流程
#上圖表示了重做日誌的寫入流程,每個mini-transaction對應每一條DML操作,例如一條update語句,其由mini-transaction來保證,對資料修改後,產生redo1,首先將其寫入mini-transaction私有的Buffer中,update語句結束後,將redo1從私有Buffer拷貝到公有的Log Buffer。當整個外部交易提交時,將redo log buffer再刷入到redo log file中。
undo log
undo log的定義
undo log主要記錄的是資料的邏輯變化,為了在發生錯誤時回滾之前的操作,需要將先前的操作都記錄下來,然後在發生錯誤時才可以回滾。undo log的作用
undo是一種邏輯日誌,有兩個作用:關於MVCC(多版本並發控制)的內容這裡就不多說了,本文將重點放在undo log用於交易的回溯。
undo日誌,只將資料庫邏輯地恢復到原來的樣子,在回滾的時候,它實際上是做的相反的工作,比如一條INSERT ,對應一條DELETE,對於每個UPDATE,對應一條相反的UPDATE,將修改前的行放回去。 undo日誌用於交易的回滾操作進而保障了交易的原子性。
undo log的寫入時機
DML作業修改叢集索引前,記錄undo日誌
二級索引記錄的修改,不記錄undo日誌
要注意的是,undo頁面的修改,同樣需要記錄redo日誌。
undo的儲存位置
在InnoDB儲存引擎中,undo儲存在回滾區段(Rollback 在Segment)中,每個回滾段記錄了1024個undo log segment,而在每個undo log segment段中進行undo 頁的申請,在5.6以前,Rollback Segment是在共享表空間裡的,5.6.3之後,可透過 innodb_undo_tablespace設定undo儲存的位置。
undo的類型
##在InnoDB儲存引擎中,undo log分為:
undo log 是否是redo log的逆過程?
undo log 是否是redo log的逆過程?其實從前文就可以得出答案了,undo log是邏輯日誌,對事務回滾時,只是將資料庫邏輯地恢復到原來的樣子,而redo log是實體日誌,記錄的是資料頁的實體變化,顯然undo log不是redo log的逆過程。redo & undo總結
以下是redo log undo log的簡化過程,以便於理解兩種日誌的過程:假设有A、B两个数据,值分别为1,2. 1. 事务开始 2. 记录A=1到undo log 3. 修改A=3 4. 记录A=3到 redo log 5. 记录B=2到 undo log 6. 修改B=4 7. 记录B=4到redo log 8. 将redo log写入磁盘 9. 事务提交實際上,在insert/update/delete操作中,redo和undo分別記錄的內容都不一樣,量也不一樣。在InnoDB記憶體中,一般的順序如下:
本文分析了事務中的redo和undo日誌,參考了一些資料書整理得出,可能有些地方表述的不清楚。如有不對之處,歡迎指出。
#以上是MySQL事務中的redo與undo的分析(圖文)的詳細內容。更多資訊請關注PHP中文網其他相關文章!