1. 程式人生 > >HDFS資料儲存與讀寫過程

HDFS資料儲存與讀寫過程

  InnoDB是在MySQL儲存引擎中第一個完整支援ACID事務的引擎,該引擎之前由Innobase oy公司所開發,後來該公司被Oracle收購。InnoDB是MySQL資料庫中使用最廣泛的儲存引擎,已被許多大型公司所採用如Google、Facebook、YouTube等,如果使用MySQL資料庫服務,沒有特殊的要求下,InnoDB是不二之選。

1.InnoDB體系架構

需要深入瞭解InnoDB先從瞭解InnoDB的體系架構開始,如下圖所示:

    InnoDB儲存引擎有多個記憶體塊,可以認為這些記憶體塊組成了一個大的記憶體池,負責以下幾個工作:
    維護所有 程序/執行緒 需要訪問的多個內部資料結構;
    快取磁碟上的資料,方便快速地讀取,同時在對磁碟檔案的資料修改之前在這裡快取;
    重做日誌(redo log)緩衝(簡單來講,redo log記錄的是事務所對應的資料更新日誌,用於降低每次資料變更都產生的磁碟IO,該日誌由工作執行緒定時把資料的更新內容定時重新整理到磁碟中去,當資料庫奔潰時資料還沒來得及重新整理到磁碟,重新啟動執行是則可以從redo log裡面重新提取重新整理到磁碟,具體有關redo log在後面相關章節會詳細介紹)

    後臺執行緒的主要作用是負責重新整理記憶體池中的資料,保證緩衝池中的記憶體緩衝的是最近的資料,此外除將已修改的資料檔案重新整理到磁碟中,同時保證在資料庫發生異常的情況下InnoDB能恢復到正常執行狀態。

 

2.後臺執行緒

master thread
    master thread是一個非常核心的後臺執行緒,主要負責將緩衝池中的資料非同步重新整理到磁碟,保證資料的一致性,包括髒頁面的重新整理、合併插入緩衝、undo頁的回收等。

io thread
    在InnoDB引擎中大量使用了AIO(Async IO)來處理寫IO請求,這樣可以極大提高資料庫的效能。而io thread的主要工作就是負責這些IO請求的回撥處理。
可以使用命令show engine innodb status\G來觀察io thread

    從上圖可以看到,有1個insert buffer執行緒;1個log執行緒;4個read執行緒;4個write執行緒。

purge thread
    事務被提交後,其所使用的undo log(用於事務commit失敗後回滾操作用)可能不在需要,因此需要purge執行緒來回收undo頁。在InnoDB 1.1版本之前,purge thread在master thread中完成;而從InnoDB 1.1版本開始,purge操作獨立到專門的執行緒執行,以減輕master thread壓力,提升cpu使用率、提升引擎效能;從InnoDB 1.2版本開始,還支援多個purge thread以進一步加快undo頁回收。

page cleaner thread
    在InnoDB 1.2.x版本中引入,其作用是將之前版本中髒頁面是重新整理操作都放在獨立的執行緒中完成,也是為了減輕master thread的壓力,提升效能。

 

3.記憶體

緩衝池
    InnoDB引擎的資料儲存是基於磁碟的,把記錄按照一定的格式記錄在磁碟,但是由於CPU與磁碟的速度有較大的差別,因此引入了基於記憶體緩衝技術來提高資料庫的效能。簡單來講,把要讀取資料的磁碟內容先載入到記憶體緩衝區域,下次讀取同樣資料時先判斷是否被緩衝區所快取,如果快取則從緩衝區讀取內容;同樣,當需要對資料進行修改時,不直接修改磁碟對應資料,而是先修改緩衝區域,然後通過一種叫checkpoint(具體後面會介紹)的機制把更新的資料重新整理到磁碟。

    因此對於InnoDB引擎來講,緩衝池的設定變得尤其重要,可以通過innodb_buffer_pool_size引數進行設定。

    雖然緩衝池是為了緩衝資料,但是緩衝池儲存的資料型別不僅僅只有資料庫的記錄,有以下幾種型別:索引頁、資料頁、undo頁、插入緩衝(insert buffer)、自適應雜湊索引、InnoDB儲存的鎖資訊(lock info)、資料字典資訊等。

    從InnoDB 1.0.x版本開始,允許有多個緩衝池例項,每個頁根據雜湊值平均分配到不同緩衝池例項中,這樣可以增加資料庫的併發處理。具體多例項緩衝池本文不再詳細展開描述,有興趣者可以繼續通過其它途徑深入瞭解。

記憶體管理 LRU List、Free List、Flush List 
    通常來說,資料庫中的記憶體緩衝區是通過LRU(Latest Recent Used,最近最少使用)演算法來進行管理。即頻繁使用的頁在LRU列表的前端,而最少使用的頁在LRU的尾端。當緩衝池不能存放新讀取到的頁時,將首先釋放LRU列表尾端的頁。

    在InnoDB引擎中,緩衝池中頁的大小預設是16KB,同樣也是使用LRU演算法來進行管理,稍有不同的是,引擎對傳統的LRU演算法進行了一些優化,當讀取到新的頁,但並不是直接插入到LRU列表的首部,而是插入到LRU列表的midpoint位置,這個位置可以通過引數innodb_old_blocks_pct控制,預設情況下這個數值是37,代表插入到LRU列表尾部的37%的位置。關於InnoDB下LRU的演算法不在本文詳細講解,有興趣的讀者可以自行查閱相關資料。

    介紹完LRU List,下面介紹Free List,Free列表儲存的是空閒頁,引擎需要從緩衝池中分頁時,首先從Free列表中查詢是否有空閒頁,若有則把頁從Free List獲取然後刪除放到LRU List中,同理當LRU List的頁面需要淘汰時則重新加入到Free List。

    在LRU列表中的頁被修改後,程該頁為髒頁(dirty page),即緩衝池中的頁和磁碟上的頁資料產生了不一致,這時候資料庫會通過checkpoint機制將髒頁重新整理回磁碟(關於checkpoint在下一節會介紹),而Flush List則是專門儲存這些髒頁的列表。

redo log重做日誌
    InnoDB儲存引擎的記憶體區域除了緩衝池外,還有重做日誌緩衝(redo log buffer)。InnoDB儲存引擎首先將日誌資訊先放入到這個緩衝區,然後按一定的頻率重新整理到redo log檔案中。在後面“檔案”一章會詳細描述各自檔案及其作用,其中就包含了redo log,這裡先不做過多的講解。

額外的記憶體池
    額外的記憶體池記錄的是資料庫內部需要用到的各種資料結構,比如記錄緩衝池資訊的、記錄LRU、鎖等,這塊往往也會被忽略。

 

4.checkpoint

    在前面的小結層描述過,緩衝池設計的目的是為了協調CPU速度與磁碟速度的鴻溝,頁的所有操作首先都是在緩衝池中完成的,如一條update、delete、insert語句改變了頁中的記錄,那麼此時此頁是髒的,資料庫需要把頁的資料更新到磁碟中。
    如果每一次變化都立刻更新到磁碟,那麼這個效率會非常大,也失去了緩衝池的意義,但是如果長時間不重新整理又會導致資料庫崩潰時刻無法及時把資料更新到磁碟而出現數據的不一致性。
    為了避免這些問題,當前事務型的資料庫普遍都採用了wirte ahead log的策略,即當事務提交的時候,先寫redo log,再修改頁,如果期間發生宕機了可以通過redo log進行資料恢復。
    checkpoint技術就是用於記錄redo log裡面,那些log已經重新整理到磁碟了,那些log還沒重新整理,在InnoDB引擎裡面,其checkpoint標記是通過一個叫LSN(log sequence number)來標記,LSN是一個8位元組的數字,LSN之前的log都是已經被重新整理到磁碟了,之後都是未被重新整理的,所以當資料庫宕機恢復的時候,只需要把LSN之後的redo log進行重新整理即可。

 

5.InnoDB關鍵特性

InnoDB儲存引擎的關鍵特性包括:
插入緩衝(insert buffer)
兩次寫(double write)
自適應雜湊索引(adaptive hash index)
非同步io(async io)
重新整理鄰接頁(flush neighbor page)    

    下面只選取其中一些比較好理解的特性來簡單介紹,其他比較複雜的如插入緩衝、自適應雜湊索引留待讀者自行去做詳細的研究。

兩次寫
    顧名思義,就是寫兩次的意思,在InnoDB引擎中,有個叫共享表空間,這個空間可以存放一些共享的資料,比如索引等資訊,當資料庫需要把一個緩衝池的頁重新整理到磁碟時,先把頁資料寫入到共享表空間,然後再寫入磁碟,當寫入磁碟發現異常導致資料丟失了,這時候從共享表空間把資料恢復重新寫入磁碟。

非同步io
    簡單來講,非同步io就是把io操作變成非同步的方式,比如需要對磁碟進行讀寫,則先發起一個io操作,等待磁碟讀寫完成後再通知上層進行處理,非同步io還有一個好處是可以對一些io操作進行合併優化,比如可以對連續頁的請求進行合併成一次請求等。

重新整理鄰接頁
    這個也是比較好理解的,就是當重新整理一個髒頁時,InnoDB儲存引擎會檢測該頁所在的區的所有頁,如果都是髒頁,那麼一起進行重新整理,可以藉助非同步io進行多個寫操作的合併,提升效率。