Bigtable Merge-Dump存儲引擎

作者: Chuanhui | 可以轉載, 但必須以超鏈接形式標明文章原始出處和作者信息及版權聲明
本文鏈接地址: http://www.nosqlnotes.net/archives/122

單機存儲引擎解決單機讀寫問題,Merge-Dump存儲引擎設計成一種通用的存儲引擎,同時支持數據寫入,隨機讀取和順序掃描功能。順序掃描功能應用很廣,比如MapReduce批處理,同一個廣告主的所有關鍵詞廣告統計,用戶瀏覽所有的收藏信息,淘寶賣家管理大量的商品等。簡單的KV系統只需要支持隨機讀取,而類似Bigtable這樣的通用表格系統需要考慮基於主鍵的順序掃描功能。Bigtable中的Merge-Dump存儲引擎結構如下:

用戶的操作首先寫入到MemTable中,當內存中的MemTable達到一定的大小,需要將MemTable dump到持久化存儲中生成SSTable文件。這裏需要注意,除了最早寫入的SSTable存放了最終結果以外,其它的SSTable和MemTable存放的都是用戶的更新操作,比如對指定行的某個列加一操作,刪除某一行等。每次讀取或者掃描操作都需要對所有的SSTable及MemTable按照時間從老到新進行一次多路歸併,從而獲取最終結果。爲了防止機器宕機,將用戶的操作寫入MemTable之前,會先寫入到操作日誌(commit log)中,這時一般會用到group commit操作,即將大量併發寫操作聚合成一塊一次性寫入到commit log。由於寫commit log爲順序追加,很好地利用了磁盤的順序訪問特性。

爲了防止磁盤中的SSTable文件過多,需要定時將多個SSTable通過compaction過程合併爲一個SSTable,從而減少後續讀操作需要讀取的文件個數。Bigtable中將compaction分爲三種:minor compaction,merge compaction以及major compaction。其中,minor compaction指的是當內存中的MemTable達到一定的大小以後需要生成SSTable;merge compaction將連續多個大小接近的SSTable及Memtable合併生成一個SSTable;major compaction合併所有的SSTable和Memtable生成最終的SSTable文件。Minor和Merge compaction生成的SSTable文件中包含的還是用戶的更新操作,只有Major compaction生成的SSTable才包含最終結果。一般來說,線上服務的寫操作比較少,我們總是能以很大概率使得每個子表只包含一個SSTable和MemTable,也就是說,讀取操作基本只需要訪問一個SSTable文件和內存;而線下或者半線下服務,比如網頁庫,雖然寫入操作多,可能經常出現一個子表包含多個SSTable的情況,不過這種類型的服務一般用於大數據量順序掃描,對延時要求不高。SSTable的compaction有幾個需要注意的點:

1, 限制SSTable的數量,必要時限制寫入速度。如果寫入速度持續大於compaction消化的速度,也就是大於系統的承載能力,SSTable將越積越多從而compaction永遠無法成功。比如Cassandra存儲節點採用了類似Bigtable的Merge-dump的做法,不過據說可能因爲沒有控制SSTable的最大個數也出現永遠合併不成功的問題;

2, Compaction及寫操作併發控制。Compaction的過程很長,compaction不能阻塞寫操作,並且minor compaction和merge/major compaction可能同時進行。Compaction成功提交的時候需要互斥修改子表記錄的SSTable結構數組,多個compaction同時進行的時候有些麻煩;

3, Minor compaction時機。當Memtable達到一定大小,比如4MB時,需要凍結Memtable並生成SSTable數據dump到磁盤中;同時,由於所有子表的操作日誌寫入到同一個commit log文件,當MemTable距離第一條數據寫入超過一定的時間也需要執行minor compaction,否則,會出現機器宕機回放的commit log過多的問題;

4, Merge compaction如何選取SSTable文件。Merge compaction合併SSTable以減少讀取的文件個數,每次merge compaction都是把相應的SSTable文件分別讀寫一次。爲了提高性能,一般會要求Merge compaction選取連續的大小接近的SSTable文件。舉個例子,如果有4個大小爲4MB的SSTable文件,如果merge的策略爲((s1 & s2) & s3) & s4 (&表示merge操作),讀取的文件大小爲s1 * 3 + s2 * 3 + s3 * 2 + s4 * 1 = 4M * 9 = 36M,如果merge的策略爲(s1 & s2) & (s3 & s4),讀取的文件大小爲s1 * 2 + s2 * 2 + s3 * 2 + s4 * 2 = 32M,並且SSTable文件個數越多差別越明顯;

數據在SSTable中連續存放,需要同時隨機讀取和順序讀取兩種需求。SSTable被分成大小約爲64KB的塊(SSTable block),由於單個tablet的大小一般爲100MB ~ 200MB,我們可以認爲SSTable的大小不超過256MB,包含的block個數爲256MB / 64KB = 4KB,每個block需要包含起始行,結束行相關的索引信息,假設索引信息大小平均爲256Byte,每個SSTable的索引大小爲4KB * 256Byte = 1MB,磁盤內存比爲256 : 1,16GB的索引可以存放16GB * 256 = 4TB的數據。SSTable的索引數據全部存放到內存中,隨機讀取需要先通過二分查找找到相應的block,然後從磁盤中讀取相應的block數據。Bigtable系統使用的SATA盤的磁盤尋道時間一般爲10ms左右,一次隨機讀取整個64KB的塊造成的overhead是可以接受的。按照64KB劃分塊還帶來了一個好處,數據量膨脹對性能的影響很小。順序讀取的做法類似,在Merge-dump引擎中是很高效的。與傳統的數據庫的數據格式不同,SSTable存放的數據一般都是稀疏的,大多數列可能都沒有更新操作。

按列存儲&壓縮:數據倉庫的應用場景中需要支持按列存儲,有兩個好處:第一個好處是減少讀取的數據量,第二個好處是提高壓縮比率。Bigtable支持指定locality group,每個locality group中的列在SSTable中連續存儲,每一個locality group之內按照行有序存儲,當然,數據在MemTable中是不需要區分locality group的。這樣,compaction是按照locality group進行的,讀取每一個待歸併的SSTable中相應的locality group的數據,合併生成一個新的SSTable locality group。某些跨多個locality group的更新操作,比如刪除一行,需要將更新操作同時寫入到多個locality group中。

總之,Merge-dump是一種同時滿足隨機和順序讀取的通用存儲引擎,可以廣泛應用在各種NOSQL存儲系統中,另外,Merge-dump存儲引擎往commit log文件追加操作日誌以及compaction過程都是順序寫文件,非常符合SSD的特性,天然適應硬件的發展趨勢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章