Mysql技術內幕InnoDB儲存引擎讀書筆記--《二》InnoDB儲存引擎

FreeeLinux發表於2017-06-30

2.1InnoDB儲存引擎概述

InnoDB儲存引擎是第一個完整支援ACID事務的Mysql儲存引擎,行鎖設計,支援MVCC,提供一致性非鎖定讀,支援外來鍵,被設計用來最有效利用記憶體和CPU。

2.2InnoDB體系架構

InnoDB儲存引擎具備一個大記憶體池,負責如下工作:

  • 維護所有程式/執行緒需要訪問的多個內部資料結構
  • 快取磁碟上的資料,方便快速的讀取,並且在對磁碟檔案的資料進行修改之前在這裡快取
  • 重做日誌(redo log )緩衝

2.2.1後臺執行緒

預設情況下,InnoDB儲存引擎的後臺執行緒有7個——4個I/O thread,1個master thread,1個行鎖(lock)監控執行緒,1個錯誤監控執行緒。I/O thread的數量由配置檔案中的innodb_file_io_threads引數控制,預設為4。(我的電腦ubuntu14.04安裝的mysql預設8個I/O執行緒)。

2.2.2記憶體

InnoDB儲存引擎記憶體由以下幾個部分組成:緩衝池(buffer pool)、重做日誌緩衝池(redo log buffer)以及額外的記憶體池(additional memory pool)。

緩衝池是佔最大塊記憶體的部分,用來存放各種資料的快取。因為InnoDB儲存引擎的工作方式總是將資料庫檔案按頁(每頁16K,不是4K)讀取到緩衝池,然後按最近最少使用(LRU)的演算法來保留在緩衝池中的快取資料。如果資料庫檔案需要修改,總是首先修改在緩衝池中的頁(發生修改後,該頁即為髒頁),然後再按照一定的頻率將緩衝池的髒頁重新整理到檔案。

緩衝池中快取的資料頁型別有:索引頁、資料頁、undo頁、插入緩衝(insert buffer)、自適應雜湊索引(adaptive hash index)、InnoDB儲存的鎖資訊(lock info)、資料字典資訊(data dictionary)等。

2.3master thread

即使某個事物沒有提交,InnoDB儲存引擎仍然會每秒將重做日誌緩衝中的內容重新整理到重做日誌檔案。所以再大的事物commit的時間也是很快的。

InnoDB的master thread會每隔一段時間將緩衝池的髒頁重新整理到磁碟中。

2.4關鍵特性

InnoDB的關鍵特性:插入緩衝、兩次寫、自適應雜湊索引。

插入緩衝

InnoDB儲存引擎開創性的設計了插入緩衝,對於非聚集索引的插入或更新操作,不是每一次直接插入索引頁中。而是先判斷插入的非聚集索引頁是否在緩衝池中。如果在,直接插入;如果不在,則先放入一個插入緩衝區中,然後再以一定的頻率執行插入緩衝和費聚集索引葉子節點的合併操作。這是通常能將多個插入合併到一個操作中(因為在一個索引頁中),這就大大提高了對非聚集索引執行插入和修改操作的效能。

插入緩衝的使用需要滿足以下兩個條件:

  • 索引是輔助索引
  • 索引不是唯一的

兩次寫

插入緩衝帶個InnoDB儲存引擎的是效能,兩次寫帶給InnoDB儲存引擎的則是資料的可靠性。

當資料庫當機時,可能發生資料庫正在寫一個頁面,而這個頁只寫了一部分(比如16k的頁,只寫前4k的頁)的情況,我們稱之為部分寫失效。

doublewrite由兩部分組成,一部分是記憶體中的doublewrite buffer,大小為2MB,部分是物理磁碟上共享表空間中連續的128個頁,即兩個區(extent),大小同樣為2MB。當緩衝池中的髒頁重新整理時,並不直接寫磁碟,而是會通過memcpy函式將髒頁先拷貝到記憶體中的doublewrite buffer,之後通過doublwrite buffer再分兩次,每次寫入1MB到共享表空間之間的物理磁碟上,然後馬上呼叫fsync函式,同步磁碟,避免緩衝寫帶來的問題。在這個過程中,因為doublewrite頁是連續的,因此這個過程是順序寫的,開銷並不是很大。在完成doublewrite頁的寫入後,再將doublewrite中的頁寫入各個表空間檔案中,此時的寫入則是離散的。

如果作業系統在將頁寫入磁碟的過程中崩潰了,在恢復過程中,InnoDB儲存引擎可以從共享表空間中的doublewrite中找到該頁的一個副本,將其拷貝到表空間檔案,再應用重做日誌。

自適應雜湊索引

InnoDB儲存引擎會自動根據訪問的頻率和模式來為某些頁建立雜湊索引。

擴充

  1. 系統故障造成資料庫不一致的原因有兩個:
    1.未完成事務對資料庫的更新可能已寫入資料庫。
    2.已提交事務對資料庫的更新可能還留在緩衝區沒來得及寫入資料庫。
    在這裡我們先說恢復的一般方法:
    (1)正向掃描日誌檔案(從頭到尾),找出故障發生前已經提交的事務(存在begin transaction
    和commit記錄),將其標識記入重做(redo)佇列。同時找出故障發生時未完成的事務
    (只有begin transaction,沒commit),將其標識記入(undo)佇列
    (2)對undo佇列的各事務進行撤銷處理。進行undo的處理方法是,反向掃描日誌檔案,對每個undo
    事務的更新操作執行反操作,即將日誌記錄中“更新前的值”寫入資料庫。
    (3)對重做日誌中的各事務進行重做操作。進行redo的處理方法是,正向掃描日誌,對每個redo事務
    重新執行日誌檔案登記操作。即將日誌中“更新後的值”寫入資料庫。
    以上三個步驟放於四海皆行。

參考

相關文章