閱讀235 返回首頁    go 阿裏雲 go 技術社區[雲棲]


MySQL鎖係列(三)之 redo log

WHY

  • 1)鎖和事務是分不開的,事務和redo又是傻傻分不清楚的

  • 2)事務最重要的是什麼?ACID 又是如何實現的?

* A 原子性
    通過redo實現

* C 一致性
    通過undo實現

* I 隔離性
    通過lock實現

* D 持久性
    通過redo和undo實現

redo log 是什麼

  • redo 概念
* 學名:重做日誌

* 個人理解:任何事務的操作都會記錄redo日誌,InnoDB引擎獨有,用於恢複數據庫到宕機的位置
  • redo 結構
* redo log  buffer

    1. 日誌會先寫到redo log buffer ,根據製定條件刷新到redo log file
    2. 由log block組成
    3. 每個log block 512字節,所以不需要double write,因為每次刷新都是原子的

* redo log file

    1. redo log的物理文件,一般有2個,大小可配置
    2. 由innodb_log_file_size配置,越大越好
    3. redo類型是物理邏輯日誌,記錄的是對頁的操作,頁內是邏輯的內容,我們姑且認為就是物理日誌好了,記錄的是對頁的操作
        比如:insert 一條記錄,那麼大致內容就會記錄
            對space id=3,page no=4 ,offset aa, 日誌內容xx (主鍵索引)
            對space id=3,page no=8 ,offset bb, 日誌內容yy (二級索引)

  • redo log buffer刷新觸發條件
1. 每秒刷新一次
2. redo log buffer使用大於1/2進行刷新
3. 事務commit(提交)時候進行刷新
    a. innodb_flush_log_at_trx_commit=0 : 事務提交時,不刷新redo log buffer
    b. innodb_flush_log_at_trx_commit=1 : 事務提交時,將redo log buffer刷新到磁盤(由於redo沒有O_direct,也必須經過操作係統緩存,然後fsync到磁盤)
    c. innodb_flush_log_at_trx_commit=2 : 事務提交時,將reod log buffer刷新到os的緩存

  • redo log 的重要組成部分
1. redo log 是循環寫入的,寫完一個,寫另一個
2. redo log 的第一個文件的頭部,會記錄兩個512字節的記錄,分別是:checkpoint1 和 checkpoint2,輪詢寫入,互為備份
3. 上麵說的很重要,checkpoint 是寫在redo 日誌裏麵的,checkpoint是什麼,後麵介紹
4. redo 裏麵記錄的是日誌的寫入,裏麵有個很重要的概念叫做 lsn
  • lsn 是什麼
* LSN = log sequeuce number , 日誌的序列號,數據庫的邏輯時鍾, 特點是單調遞增

LSN表示事務寫入重做日誌的字節總量

* LSN是什麼?有什麼含義?

---
LOG
---
Log sequence number 86594404775   -- redo log buffer 的lsn,存放在redo log buffer 中 我們稱: redo_mem_lsn
Log flushed up to   86594404775   -- redo log file 的lsn,存放在redo log 中  我們稱: redo_log_lsn
Pages flushed up to 86594404775   -- 最後一個被刷新頁的newest_modification, 這個用的比較少,暫時忽略, 這個存放在date page裏麵
Last checkpoint at  86594404766   -- checkpoint的lsn , 存放在redo log第一個文件的頭部   , 我們稱: cp_lsn

目前看下來lsn有三個含義

1. redo_mem_lsn
2. redo_log_lsn
3. cp_lsn
4. page_lsn: 每個page裏麵頭部都會記錄一個lsn,表示該page最後一次被修改的redo log lsn

以上4個lsn都是互相關聯的

* LSN 有什麼用?

    主要用於MySQL重啟恢複

* 恢複的算法如下?

    假設: redo_log_lsn = 15000 , cp_lsn=10000 , 這時候MySQL crash了,重啟後的恢複流程如下:

    a. cp_lsn = 10000 之前的redo 日誌,不需要恢複: 因為checkpoint之前的日誌已經可以確保刷新完畢

    b. 那麼 10000 <=  redo_log_LSN <= 15000 的日誌需要結合page_lsn判斷,哪些需要重做,哪些不需要重做。
        b.1  redo_log_LSN 日誌裏麵記錄的page 操作,如果redo_log_LSN <= page_lsn   , 這些日誌不需要重做,因為page已經是最新的
        b.2  redo_log_LSN 日誌裏麵記錄的page 操作, 如果redo_log_LSN >= page_lsn   , 這些日誌是需要應用到page 裏麵去的,這一係列操作我們稱為恢複.

    c. 舉個例子
        如果:redo_log_lsn 11000 , 記錄的是:space id=3,page no=4 的頁的操作,但是這個頁的page_lsn = 11500,那麼說明這個頁的lsn比redo的lsn新,那麼就不需要應用
        如果:redo_log_lsn 11000 , 記錄的是:space id=3,page no=4 的頁的操作,但是這個頁的page_lsn = 10500,那麼說明這個頁的lsn比redo的lsn老,那麼需要應用這部分日誌以達到恢複的目的






Write-Ahead Log (WAL)

當一個數據頁被刷新時,必須要求內存中小於該數據頁lsn對應的所有redo日誌,都必須先刷新到磁盤
我們稱為:日誌先行, 保證redo log 日誌必須先於 data page 刷新

Force-log-at-commit

當一個事務進行commit的時候,必須先將該事務的所有日誌寫入到重做日誌文件進行持久化

checkpoint

  • 什麼是checkpoint
* 沒有checkpoint的時候,數據庫髒頁都存放在內存中,如果這時候數據庫掛了,那麼redo就需要從頭到尾開始恢複,非常慢
* 有checkpoint的時候,會按照一定的算法進行data page髒頁的刷新, 減少數據庫恢複的時間
    a)checkpoint_lsn 表示: 在checkpoint_lsn 之前的redo日誌對應的髒頁都已經刷新到磁盤了
    b) 也就意味著,當數據庫重啟恢複的時候,小於checkpoint_lsn的redo日誌不需要再重做,大大的減少了數據庫的恢複時間

  • checkpoint種類
* sharp checkpoint

當MySQL正常關閉的時候,需要將所有的髒頁都刷新

* fuzzy checkpoint

為了考慮數據庫的性能,MySQL按照一定算法之刷新部分髒頁

fuzzy checkpoint 觸發條件

  • 定時刷新
每10秒,或者每1秒,從髒頁列表中去刷新部分髒頁

  • LRU列表的刷新
* buffer pool 內存解釋:

    * free list : 表示數據庫開啟時候,MySQL會分配空閑的頁給free list

    * LRU list : 當頁被第一次訪問(讀或者寫)的時候,會加入到LRU list

    * flush list :當頁變成髒頁的是,會按照第一次被更新的時間(oldest_modification)排序,加入到flush list,flush list裏麵存放的都是指向lru_list的指針,並不占用太多內存

* 刷新

    當buffer pool中少於innodb_lru_scan_depth指定的空閑頁時候
    會將LRU list中尾端的頁(不常用的頁)進行拿來用,如果是髒頁,則進行checkpoint

  • 高水位和低水位的刷新
* checkpoint age = redo_lsn - cp_lsn

    低水位 = 75% * 總redo大小
    高水位 = 90% * 總redo大小

* 低水位  >=  checkpoint age

    不需要刷新

* 低水位  <=  checkpoint age <= 高水位

    會強製進行 checkpoint , 根據flush_list的順序,刷新足夠多的髒頁,讓checkpoint age 小於低水位線

* 高水位  >=  checkpoint age

    會強製進行 checkpoint , 根據flush_list的順序,刷新髒頁, 讓其滿足 低水位  <=  checkpoint age >= 高水位


  • 髒頁太多的時候刷新
* innodb_max_dirty_pages_pct

當髒頁數量超過這個比例時候,會強製進行checkpoint

redo 的寫入時機

  • binlog的寫入時機
事務結束後,binlog進行寫入並刷新

T1 -> T2 -> T3 -> T4  按照事務的順序執行

  • redo的寫入時機
當事務開啟後,第一條dml語句開始執行時,就開始慢慢的寫入並刷新redo

T1_1 -> T2_1 -> T2_2 -> T3_1 -> T1_2 -> *T2 -> *T3 -> *T1

以上列表的分析為:
    這個代表事務的開始執行順序是: T1,T2,T3
    這個代表事務的結束執行順序是: T2,T3,T1

  • commit執行的時間長短,取決於什麼?
根據以上binlog和redo 的寫入時機可以判斷,commit的長短取決於binlog的日誌大小和刷新時間

redo 和 undo

1. 這裏先稍微提一下undo,至於undo 是什麼,後麵介紹
2. undo日誌本身也要寫入到redo裏麵去,這一點非常重要

最後

這裏簡單的介紹了redo的內容,這塊內容非常重要,複製,高可用與之非常密切
這裏麵的checkpoint age可以用來監控,監控這個的目的通過這篇文章我想大家都應該知道了吧

最後更新:2017-06-12 17:02:04

  上一篇:go  那麼問題來了,究竟如何逼瘋一個IT男???
  下一篇:go  簡直抓狂,最能夠把IT人逼瘋的8件事