LevelDB之Leveled-Compaction

https://github.com/imjoey/blog/issues/6

https://www.jianshu.com/p/99cc0df8ed21

https://juejin.im/post/5c99f0556fb9a070e82c1fcf

目錄

一、前言

二、LSM

1、MemTable

2、ImmutableMemTable

3、SSTable

4、SSTable Compaction

三、RockDB的合併策略圖解

1、 L0 compaction

2、 高層Compaction

3、 並行Compaction

四、size-tired和level合併策略比較


一、前言

LevelDB是Google出品的具有讀寫高性能的存儲引擎,其沒有采用傳統的B+ Tree(MySQL InnoDB)的存儲模型,而是使用了LSM(Log Structure Merge-Tree)。LSM模型中的一個重要組成就是稱作SSTable(Sorted String Table)的結構。本文先簡單介紹LSM中使用的幾種結構,然後着重介紹在衆多Compaction算法中的Leveled-Compaction。

二、LSM

LSM是通過將磁盤的隨機寫改爲順序寫來提高寫的性能,核心思想是把數據的添加或修改放到內存中,當內存中數據達到一定size後,然後dump(也就是變成了順序寫)到磁盤中。LSM中有MemTable、ImmutableMemTable、SSTable等幾個概念,下面分別介紹

1、MemTable

MemTable在內存中,記錄最近修改的數據。一般其內部使用SkipList結構存儲按key排序後的有序數據,當其存儲的數據達到一定size後,就變成ImmutableMemTable,同時新建一個新的MemTable;後續的數據修改操作均在新的MemTable內進行。

2、ImmutableMemTable

ImmutableMemTable就是隻讀不寫的MemTable,它與MemTable一起保證的寫操作無鎖化。其內部的數據是有序的,所以dump到磁盤時保證了高效的順序寫,形成了新的SSTable文件。

3、SSTable

SSTable內存儲的是一系列的有序鍵值對,形式如下圖所示。當SSTable文件較大時,爲了提高讀的性能,也可以生成key-offset索引,此索引一般都記錄在內存中。

4、SSTable Compaction

由於不斷有ImmutableMemTable會dump到磁盤中成爲新的SSTable文件,所以SSTable文件的數量會逐漸增多,其內部存儲的數據也會產生很多過期數據(key的舊數據),所以需要對SSTable文件進行定期Compaction,一方面減少SSTable文件的數量,同時也刪除過期的數據。

SSTable Compaction有多種算法,比如Cassandra默認的基於文件大小的Size-Tired Compaction、基於時間序列的Date-Tiered Compaction,以及Leveled Compaction。

這裏主要以Cassandra中的Leveled Compaction算法爲例來分析(這也是LevelDB名字的由來)。

Leveled Compaction

SSTable被劃分到不同的level中,詳細的Leveled Compaction算法描述如下:

  • 每個SSTable文件的固定大小爲160M

  • 從ImmutableMemTable創建的SSTable文件劃分到Level-0中

  • 每個Level有SSTable文件數量的限制。在除了Level-0的任意Level中,兩級Level之間的SSTable文件數量呈指數級倍數。比如:Level-1中有10個SSTable文件,Level-2有100個SSTable文件

  • 在除了Level-0的任意Level中,SSTable文件之間所包含的key的範圍不重疊。(也就是說,每個Level的所有SSTable文件,可以看做是一個大的SSTable文件)

  • 如果Level-0中SSTable數量超過限制(比如:4),那麼自動回將這4個Level-0的SSTable文件與Level-1的所有10個SSTable文件進行Compaction。(這裏需要特別注意:level-0比較特殊,各個SSTable之間是有重疊的,所以只能將4個SSTable與Level1中所有進行整體上的Merge和切分(如原博客所述)。但level-1及其以上,各個SSTable之間沒有重疊key,當SSTable個數超過閾值時,可以只選擇一個或者多個SSTable與下一level值域對應的SSTable進行合併,由於每一級的SSTable大小相同,可以有效避免寫放大)

  • 在Compaction過程中,首先對所有的SSTable文件按key進行歸併排序,然後將排序後結果寫入到新的SSTable文件中,如果SSTable文件大小到了160M上限,就新生成SSTable繼續寫。如此類推,直到寫完所有數據。

  • 刪除參與Compaction的Level-0的4個和Level-1的10箇舊的SSTable文件

  • 此時Level-0的SSTable便merge到Level-1中了,那麼如果Level-1的SSTable文件數量超過上限,那麼就從Level-1中選出 1 個超量的SSTable文件,然後將其與Level-2中的SSTable文件進行Compaction。

    • 查看選出的Level-1 SSTable文件中key的範圍

    • 從Level-2中選出能覆蓋該範圍的所有SSTable文件

    • 將以上的所有SSTable文件根據上面介紹的算法繼續進行Compaction

    注:一般情況下,Level-1和Level-2的Compaction,只會涉及Level-2內大概1/10的SSTable文件,這樣可以大幅降低參與Compcation的SSTable文件數量(相比於Size-Tired Compaction),進一步提升提升性能

  • 如果Level-2中的文件數量超過限制,則繼續按照上述算法選出超量的SSTable文件與Level-3中的SSTable文件進行Compaction

三、RockDB的合併策略圖解

1、 L0 compaction

當L0的文件數量達到level0_file_num_compaction_trigger的值時,觸發L0和L1的合併。通常必須將所有L0的文件合併到L1中,因爲L0的文件的key是有交疊的(overlapping)。

L0與L1的compaction

2、 高層Compaction

當L0 compaction完成後,L1的文件總size或者文件數量可能會超過閾值,觸發L1向L2的合併。從L1至少選擇一個文件,合併到L2中key有交疊的文件中。

L1向L2合併

同樣的,合併後可能會觸發下一各level的compaction。

合併後的L2

L2向L3合併

合併後的L3也需要做Compaction.

 

合併後的L3

3、 並行Compaction

並行compaction

max_background_compactions控制了並行compaction的最大數量。

四、size-tired和level合併策略比較

上文已經提到,我們需要對SSTables做合併:將多個SSTable文件合併成一個SSTable文件,並對同一個key,只保留最新的值。

那這裏討論的合併策略(Compaction Strategy)又是什麼呢?

A compaction strategy is what determines which of the sstables will be compacted, and when.

也就是說,合併策略是指:1)選擇什麼時候做合併;2)哪些SSTable會合併成一個SSTable

目前廣泛應用的策略有兩種:size-tiered策略和leveled策略。

  • HBase採用的是size-tiered策略。
  • LevelDB和RocksDB採用的是leveled策略。
  • Cassandra兩種策略都支持。

這裏簡要介紹下兩種策略的基本原理。後面研究LevelDB源碼時再詳細描述leveled策略。

size-tiered策略

簡稱STCS(Size-Tiered Compaction Strategy)。其基本原理是,每當某個尺寸的SSTable數量達到既定個數時,合併成一個大的SSTable,如下圖所示:

 

stcs

 

 

它的優點是比較直觀,實現簡單,但是缺點是合併時的空間放大效應(Space Amplification)比較嚴重,具體請參考Scylla’s Compaction Strategies Series: Space Amplification in Size-Tiered Compaction

空間放大效應,比如說數據本身只佔用2GB,但是在合併時需要有額外的8G空間才能完成合並,那空間放大就是4倍。

leveled策略

STCS策略之所以有嚴重的空間放大問題,主要是因爲它需要將所有SSTable文件合併成一個文件,只有在合併完成後才能刪除小的SSTable文件。那如果我們可以每次只處理小部分SSTable文件,就可以大大改善空間放大問題了。

leveled策略,簡稱LCS(Leveled Compaction Strategy),核心思想就是將數據分成互不重疊的一系列固定大小(例如 2 MB)的SSTable文件,再將其分層(level)管理。對每個Level,我們都有一份清單文件記錄着當前Level內每個SSTable文件存儲的key的範圍。

Level和Level的區別在於它所保存的SSTable文件的最大數量:Level-L最多隻能保存 10 LSSTable文件(但是Level 0是個例外,後面再說)。

 

lcs

 

 

注:上圖中,"run of"就表示一個系列,這些文件互不重疊,共同組成該level的所有數據。Level 1有10個文件;Level 2有100個文件;依此類推。

下面對照着上圖再詳細描述下LCS壓縮策略:

先來看一下當Level >= 1時的合併策略。以Level 1爲例,當Level 1SSTable數量超過10個時,我們將多餘的SSTable轉存到Level-2。爲了不破壞Level-2本身的互不重疊性,我們需要將Level-2內與這些待轉存的SSTable有重疊的SSTable挑出來,然後將這些SSTable文件重新合併去重,形成新的一組SSTable文件。如果這組新的SSTable文件導致Level-2的總文件數量超過100個,再將多餘的文件按照同樣的規則轉存到Level-3

再來看看Level 0Level 0SSTable文件是直接從memtable轉化來的:你沒法保證這些SSTable互不重疊。所以,我們規定Level 0數量不能超過4個:當達到4個時,我們將這4個文件一起處理:合併去重,形成一組互不重疊的SSTable文件,再將其按照上一段描述的策略轉存到Level 1

 

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