mysql-事物實現原理

MySQL-事務的實現-redo


MySQL中事務:html

  1. 事務的實現:

     ACID:sql

    • 原子性(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】-- 【重作日誌來實現】ui

【持久性構成】:1.重作日誌緩衝(redo log buffer) ,是易失的 2.重作日誌文件(redo log file),是持久的spa

【持久性原理】: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的部分。

 

 

--完結

相關文章
相關標籤/搜索