iT邦幫忙

2021 iThome 鐵人賽

DAY 13
1
Software Development

MYSQL-相關實務操作學習紀錄系列 第 13

Day.13 Crash Recovery - InnoDB 架構 -> MYSQL 二階段提交(2PC) _1


今天開始的主題有關於MYSQL的crash-safe能力(二階段提交),如何保證服務在任何時間發生崩潰時,重啟後之前的提交紀錄不會發生數據丟失狀況。

事務提交流程

在binlog內容中我們可以看到事件的上下文都會有紀錄BEGIN和COMMIT 代表這個事件的開始與結束,因為預設autocommit為開啟,所以當我們輸入一條SQL指令,MYSQL就會自動幫我們提交執行內容(等於在binog裡看到的一個事件)。

透過以下簡單例子了解開啟與關閉自動提交的差異~ 開啟2個連線而右邊的連線只做查詢資料動作。
https://ithelp.ithome.com.tw/upload/images/20210829/20130880Pzlu1zZpzx.png

  • mysql執行Transaction的流程分別為:
  1. 進入交易模式- start transaction 或 begin
  2. 本次交易要執行的SQL內容(update/insert....)
  3. 結束交易模式- commit
  • 當交易過程中(2.)的時候有錯誤- rollback (表示取消交易,還原到未交易時的狀態)

ps. DDL語句是無法進行rollback 的喔!!


儲存引擎

就像是資料庫的核心,以MYSQL來說常見的有InnoDB&MyISAM。MYSQL 5.5版開始所使用的(預設引擎)是InnoDB,不同引擎有各自優缺點與應用需求,這邊就不多描述囉~

#看支持的引擎有哪些
mysql> show engines;

9 rows in set (0.00 sec)

mysql> show variables like 'default_storage_engine';
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+

為什麽會看到敘述時有時候用(事務)有時候用(事件),透過show engines可以發現除了InooDB其他引擎都是不支援事務的,像常見的MyISAM ~ 所以才會以事件敘述避免混淆。不過現在預設就是使用InnoDB所以看成同樣的就行啦~


認識一點innoDB架構

由於二階段流程上會牽扯到一些innoDB架構內部機制流程,所以這邊先帶一點innoDB架構相關內容在進入正題比較好了解意思。/images/emoticon/emoticon33.gif

(引用mysql官方5.7的InnoDB架構圖) 先看一下架構中(左)內存區&(右)磁盤區分別包含什麼~
https://ithelp.ithome.com.tw/upload/images/20210908/20130880ZuhVJpChcN.png

  • 認識InnoDB內存架構中的Buffer Pool(緩衝池):

觀念: 資料庫中的數據最終都是要存放到磁盤上的,不過在磁盤的讀取速度會比內存慢很多,所以不可能每次讀寫資料都往磁盤執行,勢必造成效能上的影響。

  • 數據頁(Page)- InnoDB儲存數據的基本結構,頁會儲存資料庫相關數據內容,作為磁盤與內存交互的最基本單位。

  • 髒頁- 指的是在緩衝池中已經被修改的頁,還沒被刷新到磁盤上。
    (ex.數據頁A 在buffer pool中的內容比在disk中的還要新= 髒頁)

那身為一個儲存資料系統,資料會頻繁的做存取是很正常的。透過緩衝池在資料讀取上緩存訪問時的表和索引數據,去達到加快讀取請求的處理速度提升效能。另外執行資料的更新異動時也是先在buffer pool中完成的喔!

觀念: 如果內存中不存在要讀取or更新的數據,會先從disk載入數據所在數據頁至buffer pool中在做更新,而不是直接透過disk去存取資料。ex.讀取一條數據

查詢語句 ->                        (判斷有無命中)    
           判斷數據頁是否存在於內存中     --->    if N (從磁盤中將該紀錄對應的數據頁加載至內存)
                                     --->    if Y 返回數據

MYSQL崩潰復原Q&A /images/emoticon/emoticon33.gif

Q1: 如果內存中的數據已更新(磁盤上的數據尚未更新),那當MySQL服務在任何時間發生異常關閉的狀況下,如何去保證重啟後還尚未落盤的內存資料不會丟失?

A1: mysql如何實現crash-safe保證事務完整性,靠的就是innoDB架構中的redo log和undo log日誌紀錄,在提交階段中如果發生意外崩潰,對於已提交的事務資料就不會造成丟失(redo log),而對於提交尚未完整的事務則會進行rollback(undo log)。

Q2: 為什麽binlog無法做到crash-safe能力,而redo log可以做到?

來看一下兩者之間差異:
-- | binlog | redo log
------------- | -------------
層級 | Server | InnoDB
儲存內容 | 邏輯日誌 | 物理日誌
寫入方式 | 追加寫(參數設定切換) | 循環寫(固定大小)
內容 | SQL語句邏輯 |事務執行過程中對數據頁的修改
作用 | mysql主從,備份,還原 | mysql崩潰恢復

有關於redo log需了解以下內容:

  • 日誌緩存區(Log Buffer)

參考上圖InnoDB架構內存區域,Log Buffer包含了保存要寫入磁盤InnoDB日誌文件(redo log)的數據。

  • redo log

    • 可分為在內存中的日誌緩衝(redo log buffer) 和在磁盤上的日誌文件(redo log file)。

      ex.在mysql數據目錄下會看到 ib_logfile0,ib_logfileN 的文件。可以發現redo log不只有一個儲存文件,有ib_logfile0~ib_logfileN 個。

    透過以下參數配置redo log文件數量&大小 ex.預設為2個redo log文件檔

    mysql> show variables like '%innodb_log_file%';
     +---------------------------+----------+
     | Variable_name             | Value    |
     +---------------------------+----------+
     | innodb_log_file_size      | 50331648 |
     | innodb_log_files_in_group | 2        |
     +---------------------------+----------+
     2 rows in set (0.01 sec)     
    
    
     ps.在innodb_log_file_size 的設定上對inooDB性能面來說是有相對影響的!像設置太大的值可能會造成崩潰恢復時的時間拉長。
    
    • 追加寫(binlog) vs. 循環寫(redolog)
      在前面我們介紹過binlog的當紀錄寫滿時會切換至新的一個log檔紀錄(寫滿就切新日誌文件),而在這邊redo log循環寫的意思為比如我目前redo log文件設定為2個,資料的寫入與清除都是在這2個檔案中(ib_logfile0 / 有ib_logfile1)中循環。

這邊開始要想一下喔~

  • 注意: 當我們執行一條DML語法時會先將記錄寫入內存中的redo log buffer(紀錄修改後的值),事務提交時再將其寫至磁盤上redo log file,最後定期將內存中更改的數據(髒頁)刷新至磁盤上。

  • 以下圖幫助你認識redo log文件資料的紀錄(write pos)與清除(checkpoint)作用
    https://ithelp.ithome.com.tw/upload/images/20210909/20130880W18fViVrLb.png

  • WAL機制(Write-Ahead Logging)- 在redo log採用。

是指寫操作時不會立刻更新至磁盤上,而是先紀錄到日誌,等到某個時機點在更新至磁盤上。而由於寫入磁碟檔案是隨機寫,寫入日誌為順序寫。相比之下順序寫的方式造成的開銷與效能相對小,所以使用日誌先行的機制。

一般會看到日誌先行的解釋為先寫入日誌在寫入磁盤,不過不知道實際上流程是指什麼~

解釋: 先將內存中對應的日誌頁持久化(redo log buffer-寫入->redo log file),才持久化內存的更新數據頁至磁盤上。

A2: 看完以上比較可以看到由於redolog是固定大小的,不斷的循環寫。所以當日誌滿了的狀況下,就會需要對舊的紀錄做刪除,而刪除的前提是這些數據頁內容已經從內存刷入磁盤中!以儲存內容來說binlog沒有能判斷哪些數據是否已刷盤的標示。所以當mysql掛了重啟時會使用redo log紀錄進行復原,來保證數據持久完整性。


明天來講關於redo log和binlog日誌寫入策略影響~


上一篇
Day.12 主從搭建 - 部署流程(Master Slave Replication )
下一篇
Day.14 Crash Recovery- InnoDB 架構 -> MYSQL 二階段提交(2PC) _2
系列文
MYSQL-相關實務操作學習紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言