MySQL-事務的實現-redo



MySQL中事務:
  1. 事務的實現:
     ACID:
    • 原子性(A : Atomicity)
    • 一致性(C : consistency )
    • 隔離性(I : isolation)
    • 持久性(D : durability )
  1. 實現方式:
    • 隔離性:通過鎖來實現
    • 原子性和持久性:通過redo log 來實現
    • 一致性:通過undo來實現
  1. redo 和 undo 比較:
        都是恢復操作:
    1. redo:恢復提交事務修改的頁操作
    2. undo: 回滾行記錄到某個特定版本
       記錄內容不同:
    1. redo: 是物理日志,記錄的是物理的修改操作
    2. undo: 是邏輯日志,根據每行記錄進行記錄
       讀取方式不同:
    1. redo : 在數據庫運行時,不需要讀取操作(注:數據庫恢復時,才用redo)
    2. undo : 在數據庫運行時,需要隨機讀取(注:回滾時用)
 
 
redo-在事務中的應用
1.基本概念
【事務持久性:D】-- 【重做日志來實現】
【持久性構成】:1.重做日志緩沖(redo log buffer) ,是易失的 2.重做日志文件(redo log file),是持久的
【持久性原理】:InnoDB是事務的存儲引擎,通過Flush Log at Commit機制實現事務的持久性。即:當事務提交(Commit)時,必須先將事務的所有日志(這里只重做日志)寫入到重做日志文件中,進行持久化,待事務的commit完成才算完成。
【事務的所有日志】:在InnoDB中,事務的所有日志有兩部分:redo log 和 undo log 
 
【fsync操作】:為了確保每次重做日志都寫入重做日志文件,在將重做日志緩沖寫入重做日志文件后,InnoDB存儲引擎都需要調用一次fsync操作。
【innodb_flush_method = O_DIRECT/NULL】: 控制InnoDB數據文件和redo log 文件打開,刷寫模式。
     1.設置為NULL時,默認是:fsync選項。過程:重做日志緩沖先寫入文件系統緩存,再進行fsync(將日志刷新到重做日志文件 )操作。依賴磁盤的性能。
     2.設置為O_DIRECT,過程:調用用O_DIRECT打開數據文件, 然后調用:fsync(),將所有刷新到數據和log文件中。不經過操作系統緩存, 避免兩次寫操作
【非持久性】:通過手工設置非持久性來提高數據庫性能。
     原理:事務提交時,日志不寫入重做日志文件,而是等待一個周期后,再執行fsync操作。不是強制每次提交都fsync,可以顯著提高性能。
      弊端:如果數據庫發生宕機,由於部分日志未刷新到磁盤,會丟失最后一段的事務。
【innodb_flush_log_at_trx_commit = 0/1/2】:該參數控制重做日志刷新到磁盤的策略。
     1 : 默認是1,表示事務提交時必須調用一次fsync,<redo log刷新條件之一:事務提交前必刷新到日志文件>。 遵循ACID的持久性
     0 : 事務提交時,不進行寫重做日志操作.寫的操作僅在master Thread中完<redo log 刷新條件之二>,大概每隔1秒執行一次fsync操作. 在1秒內有數據庫宕機丟數據的風險.
     2 : 寫重做日志文件,但僅僅寫入文件系統緩存中,不進行fsync操作。僅數據庫宕機系統正常,不會丟數據。 系統宕機,緩存中未刷新到重做日志文件的那部分事務會丟失.
總結:0和2能提高事務提交性能,但是這種情況喪失了事務的ACID特性,因此在大量執行insert操作時,在最后執行一次commit操作。這樣回滾時可以回滾到事務最開始的狀態.
 
Innodb存儲引擎使用中,為了遵循持久性和一致性,關於復制的設置:
     1.如果啟用二進制日志(binlog),設置: sync_binlog=1;
     2.同時也設置:  innodb_flush_log_at_trx_commit=1.
 
【sync_binlog = N】:
     N=0,事務提交后,不做fsync之類的磁盤同步指令,刷新binlog_cache到磁盤文件,而是讓文件系統自行決定什么時間同步。 性能高,但是有丟失數據的風險.
     N=1,1次事務提交后,執行fsync操作,將binlog chace同步到磁盤文件。這 種選擇是最安全的,但是是最慢的.
【binlog和redo log比較】:
     1.產生層面不同
     redo log: 是在存儲引擎層產生,只針對InnoDB存儲引擎
     binlog:在數據庫上層產生的.MySQL中任何存儲引擎對數據庫的更改都會產生二進制日志.
     2.記錄內容形式不同
     redo log: 是物理格式的日志,記錄的是對於每個頁的修改.
     binlog: 是一種邏輯日志,記錄的是sql語句.
     3.寫入磁盤時間不同
     redo log: 在事務進行中不斷的寫入.不隨事務的提交而提交,不是順序寫入的.
     binlog: 在事務提交后進行寫入.
 
2.日志塊的結構
在InnoDB存儲引擎中,重做日志都是以512字節進行存儲的.也就是說重做日志緩沖,重做日志文件都是以塊(block)的方式進行保存.稱為:重做日志塊(redo log block),大小:512字節.
如果一個頁中產生的重做日志大於512字節,就分割成多個重做日志塊就行存儲.
重做日志塊的大小和磁盤扇區的大小一樣,512字節,因此重做日志的寫入 可以保證原子性不需要doublewrite技術.
 
日志塊的組成:日志本身,日志塊頭(log block header),日志塊尾(log block tailer)
 
 
Log Block Header 解析:
 
LOG_BLOCK_HDR_NO:4字節
log buffer由log block組成,在內部就像一個數組,而LOG_BLOCK_HDR_NO,用來標記這個數組中的位置。改制必須大於0,允許最大2G;如果在日志刷新寫入段時,是第一個日志塊,最高位就設置成1.
LOG_BLOCK_DATA_LEN:2字節
表示LOG_BLOCK所占用的大小,被寫滿時,該值為:0x200,表示全部block空間,即占用512字節。
LOG_BLOCK_FIRST_REC_GROUP:占用2字節
表示LOG_BLOCK中第一個日志所在的偏移量。如果LOG_BLOCK_FIRST_REC_GROUP=LOG_BLOCK_DATA_LEN 表示log block不包含新的日志。
LOG_BLOCK_CHECKPOINT_NO:4字節
表示:LOG_BLOCK最后被寫入時的檢查點。如果此時log block還沒寫滿,只能等下次log flush 時,才會更新。
 
關於一個事務占用兩個log block的圖:
事務T1的重做日志占用:696字節
事務T2的重做日志占用:100字節
有圖知道:事務T1 696字節,占用兩個log block,左側的log block中 LOG_BLOCK_FIRST_REC_GROUP=12,即第一個日志開始的位置。
在第二個block中,由於包含了T1的重做日志,因此事務T2的重做日志才是block中的第一個日志,即 LOG_BLOCK_FIRST_REC_GROUP=(12+200)=212
 
3.重做日志組(log group)
 
log group為重做日志組,里面有多個重做日志文件。源碼中支持log group的鏡像功能,但已禁用了,因此InnoDB存儲引擎實際只有1個log group。
 
log group 是邏輯上的概念!!!
 
重做日志存儲的就是之前在log buffer中保存的塊,因此也是根據塊的方式進行物理存儲的管理。block=512bytes。
 
InnoDB存儲引擎運行過程中, log buffer根據一定的規則將log block刷新到磁盤:
     1.事務提交時
     2.當log buffer中一半的空間已經被使用
     3.log checkpoint時
 
redo log file的寫入順序:
     log block 寫入追加到redo log file的最后部分,當一個redo log file寫滿時,會寫入下一個redo log file。 這種方式:round-robin.
     看起來是順序的,其實不然,除了保存log buffer刷新到磁盤的log block,還保存了一些其他信息,這些信息占:2KB,即redo log file 的前2KB不保存log block的信息。
 
2KB的信息:保存 4 * 512字節的 塊。
 
名稱
大小(字節)
log file header
512
checkpoint1
512
512
checkpoint2
512
 
 
 
 
 
 
上述信息只在log group的第一個redo log file里存儲,其余file留空,這也就是說 寫入不是順序的!如下圖:
 
 
4.重做日志的格式
 
 
5.LSN
LSN : Log Sequence Number的縮寫,代表日志序列號,單位:字節。在innodb存儲引擎中占有8字節,單調遞增。
LSN : 表示的含義
  1. 重做日志寫入的總量
  2. checkpoint的位置
  3. 頁的版本
LSN 表示事務寫入重做日志的字節總量。例如,當前重做日志的LSN是1000,事務T1寫入了100字節的重做日志,LSN就變成1100,又有事務T2寫入200字節的重做日志,那么LSN變成:1300.
 
LSN不僅記錄在重做日志中,還記錄在頁中。每個頁的開頭部有一個FIL_PAGE_LNS,記錄該頁的LSN。
頁中的LSN表示:該頁最后刷新時LSN的大小。
重做日志記錄的是每個頁的物理更改日志,因此頁中的LSN用來判斷是否需要進行恢復操作。例如:頁的LSN為:10000,數據庫啟動時,寫入重做日志的LSN:13000,表明該事務已經提交,數據庫需要恢復;重做日志中的LSN小於頁中的LSN,不需要進行重做,因為頁中的LSN表示已經刷新到該位置。
 
通過:SHOW ENGINE INNODB STATUS\G來查看LSN的情況
---
LOG
---
Log sequence number 47324552     ----------------->表示當前的LSN
Log flushed up to   47324552     ----------------->表示刷新到重做日志的LSN
Pages flushed up to 47324552     ----------------->表示刷新到磁盤的LSN
Last checkpoint at  47324552
Max checkpoint age    80826164
Checkpoint age target 78300347
....
 
上述的3個值,生產環境中可能是不同的:因為一個事務從重做日志緩沖刷新到重做日志文件,並不只是在事務提交時發生,每秒都會有重做日志緩沖刷新到重做日志文件的操作。
 
6.恢復
 
InnoDB存儲引擎在啟動時,不管上次數據庫是否正常關閉,都會嘗試進行恢復。重做日志是物理日志,恢復時比較快。
checkpoint 表示已經刷新到磁盤上的LSN。
 
例子:redo log file 記錄的LSN:13000,刷新到磁盤上的LSN:10000,數據庫在10000處宕機,恢復時,只需恢復10000~13000的部分。
 
 
--完結
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM