聊聊RocksDB Compact


| 導語 對於 LevelCompact 策略,RocksDB會根據每一層不同的策略計算出CompactScore,根據CompactScore大小來決定那一層將會優先進行Compact,然后選擇Level-N 和Level-(N+1)的文件進行Compact。如何計算CompactScore? 如何選擇文件進行Compact?Compact有哪些參數?如何知道RocksDB當前的一個狀態?

 

RocksDB是基於LSM結構的K-V存儲引擎,由於數據文件采用Append Only方式寫入,而對於過期的數據、重復的數據必然會存在有多份副本,這部分數據通過Compact的方式進行逐步的清理。 
那么這里好奇的提出幾個問題,由這幾個問題引出下文:

  1. RocksDB是如何進行Compact 的?
  2. Compact的時候這些文件是如何進行選擇的?
  3. Compact在什么時候、或者什么條件下觸發?
  4. 對於Compact我們能知道哪些信息?通過TRedis怎么查看這部分信息?
  5. 有哪些參數可以控制或者影響到Compact

由於我們的TRedis底層采用RocksDB存儲引擎進行持久化,底層數據文件采用分層的方式管理,故這里討論的Compact 基於Level Compact 。

數據怎么來?我們調用TRedis接口進行寫數據時,數據會先寫入到內存中的Memtable里邊,當Memtable寫滿后會寫入下一個Memtable,Memtable采用Skiplist結構以此保證數據按照Key的字典序進行排序,同時這個Memtable會被后台線程刷到磁盤文件–Level-0,當Level-0文件個數達到一定數量,Compact線程可能會進行Compact,由此產生Level-1,當Level-1文件總大小達到一定大小后, Compact線程可能會進行Compact,由此產生Level-2,…….

RocksDB對每一層的處理規則不太一樣,由於Level-0層的數據直接由Memtable dump得到,從而不能保證Level-0層的每個文件Key的范圍不能有交集,故對Level-0層的會進行特殊處理,而對於Level-1+層處理規則一樣。

Level-0 層的文件在不停的從Memtable 中dump出來,那么何時才會把這些Level-0層的文件合並到Level-1 ? 
RocksDB對對每一層進行打分,分數從0~1000000,這個分數的大小決定了進行Compact 的優先級,分數越大,越先進行Compact。

那么這個分數如何計算出來?
  • 如果是Level-0層,會先算出當前有多少個沒有進行Compact 的文件個數numfiles, 然后根據這個文件的個數進行判斷,當numfiles<20 時,Score = numfiles/4;當24>numfiles>=20時,Score = 10000;當 numfiles>=24時,Score = 1000000
相關參數 說明
level0_file_num_compaction_trigger 4 當有4個未進行Compact的文件時,達到觸發Compact的條件
level0_slowdown_writes_trigger 20 當有20個未進行Compact的文件時,觸發RocksDB,減慢寫入速度
level0_stop_writes_trigger 24 當有24個未進行Compact的文件時,觸發RocksDB停止寫入文件,此時會盡快的Compact Level-0層文件
  • 如果是Level-1+層,會去計算每一層未進行Compact文件的總Size,然后再和這一層的”容量值”做對比,得到一個比值,這個值就是該層的 CompactScore ,也就是說對於Level-1+層,Compact 觸發條件是看這一層文件的大小而不是個數。Score = level_bytes / MaxBytesForLevel(level)
對於Level-1+層,每一層的最大Bytes 是如何計算出來的?

Level-1 層 文件總大小由 max_bytes_for_level_base 參數控制,而 Level-2 層的大小通過: Level_max_bytes[N] = Level_max_bytes[N-1] * max_bytes_for_level_multiplier^(N-1)*max_bytes_for_level_multiplier_additional[N-1] 計算得出:

參數 說明
max_bytes_for_level_base 10485760 用於指定Level-1 層總大小,超過這個值滿足觸發Compact條件
max_bytes_for_level_multiplier 10 每一層最大Bytes 乘法因子
max_bytes_for_level_multiplier_addtl[2] 1 Level-2 層總大小調整參數
max_bytes_for_level_multiplier_addtl[3] 1 Level-3 層總大小調整參數
max_bytes_for_level_multiplier_addtl[4] 1 Level-4 層總大小調整參數
max_bytes_for_level_multiplier_addtl[5] 1 Level-5 層總大小調整參數
max_bytes_for_level_multiplier_addtl[6] 1 Level-6 層總大小調整參數
if (i > 1) {
level_max_bytes[i] = MultiplyCheckOverflow(
MultiplyCheckOverflow(level_max_bytes[i - 1],
max_bytes_for_level_multiplier),
max_bytes_for_level_multiplier_additional[i - 1]);
} else {
level_max_bytes[i] = max_bytes_for_level_base;
}
在進行Compact的時候,會選擇哪些文件進行Compact操作呢?

對於Level-0層文件,RocksDB總是選擇所有的文件進行Compact操作,因為Level-0層的文件之間,可能會有key范圍的重疊。 
對於Level-N (N>1)層的文件,會先按照文件大小排序(冒泡排序),選出最大的文件,並計算這個文件Key 的起止范圍,通過這個范圍查找Level-N+1層文件,把選出的Level-N 文件和Level-N+1 文件做為輸入,並且在Level-N+1新建一個或多個SST文件作為輸出。 
可以通過設置max_background_compactions 大於1 來使用並行Compact,不過這個並行Compact 不能作用到Level-0層。

  // Find the compactions by size on all levels.
for (int i = 0; i < NumberLevels() - 1; i++) {
double score = vstorage->CompactionScore(i);
level = vstorage->CompactionScoreLevel(i);
assert(i == 0 || score <= vstorage->CompactionScore(i - 1));
if ((score >= 1)) {
c = PickCompactionBySize(mutable_cf_options, vstorage, level, score);
if (c == nullptr ||
ExpandWhileOverlapping(cf_name, vstorage, c) == false) {
delete c;
c = nullptr;
} else {
break;
}
}
}

如何查看RocksDB內部狀態?

一般情況下內部狀態會定時dump出來存放到LOG文件里,這個時間可以通過:stats_dump_period_sec 來控制這個dump內部狀態的頻率,如果是TRedis V1.2.9 版本以上可以通過 rocksprop rocksdb.cfstats 得到這些信息:

關於這些參數的解釋如下:

列名 解釋
Level Level0~N、或者合計值、或者Int
Files SST文件數量/待進行compact的SST文件數
Size(MB) SST文件總大小
Score Read(GB) 代表進行compact的優先級,分數越高越會優先進行compact
Rn(GB) 進行compact時,讀當前層文件的大小
Rnp1(GB) 進行compact時,讀取下一層文件的大小
Write(GB) compact完成時,寫入文件的大小
Wnew(GB) 新產生的數據大小: 寫入到Level-(N+1)層的大小 - 從Level-(N+1)層讀的大小
RW-Amp 讀寫放大比例 : 總的讀寫 / 從Level-N層讀的大小
W-Amp 寫放大比例: 寫入Level-(N+1)層大小/從Level-N層的大小
Rd(MB/s) 讀文件速度: (bytes_readn + bytes_readnp1 )/((micros + 1) / 1000000.0)
Wr(MB/s) 寫文件速度: bytes_written / ((micros + 1) / 1000000.0)
Rn(cnt) Files read from level N during compaction between levels N and N+1
Rnp1(cnt) Files read from level N+1 during compaction between levels N and N+1
Wnp1(cnt) Files written during compaction between levels N and N+1
Wnew(cnt) Wnp1 - Rnp1
Comp(sec) Compact 累計耗時:micros / 1000000.0
Comp(cnt) Compact累計的次數
Avg(sec) 平均每次Compact耗時
Stall(sec) level0_slowdown 耗時
Stall(cnt) level0_slowdown 累計次數
Avg(ms) 平均每次Stall耗時
RecordIn Compact 進行時,所有Level-N,Level-(N+1) 輸入的entries數
RecordDrop Compact 進行時: RecordIn - 輸出到Level-(N+1)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM