RocksDB阻寫

  • 2019 年 10 月 11 日
  • 筆記

RocksDB有一個廣泛使用的功能就是當flush或compact速度小於外部數據寫入速度的時候可以阻寫。如果沒有這個功能的話,那麼當用戶持續寫入的數據超過磁盤所能處理的數據時,數據庫就會出現以下情況:

  • 空間放大,導致磁盤寫滿(compact來不及刪除冗餘數據);
  • 讀放大,嚴重降低讀性能(冗餘數據來不及刪除導致讀遍歷的sst文件數量變多)。

解決上述問題的方法就是將寫入速度降低到數據庫可以正常處理的速度。有時候數據庫會面臨突發的大量寫請求,或者硬件處理速度比較慢(比如機械硬盤),這時你在訪問數據庫時就可能出現意想不到的緩慢或查詢超時。

可以通過以下方法來判斷你的DB是否存在阻寫問題:

  • 查看LOG文件,看是否有阻寫的log輸出;
  • 查看LOG文件的Compatction狀態,如下圖:

以下原因可能會導致阻寫:

  • memtable太多。當需要flush的memtable數量大於等於max_write_buffer_number時,會寫阻塞,直到memtable flush完成。另外,如果max_write_buffer_number大於3,並且待flush的memtable大於等於max_write_buffer_number – 1時,寫限速。在這種情況下,你可以在LOG文件中查看到大概如下的log:Stopping writes because we have 5 immutable memtables (waiting for flush), max_write_buffer_number is set to 5

Stalling writes because we have 4 immutable memtables (waiting for flush), max_write_buffer_number is set to 5

  • level-0層的SST文件太多。當level-0層的文件數量到達level0_slowdown_writes_trigger時,會寫限速。當level-0層的文件數量到達level0_stop_writes_trigger時,會寫阻塞,直到level-0層的SST文件合併到level-1層,使level-0層的文件數目減少。在這種情況下,你可以在LOG文件中查看到大概如下的log:Stalling writes because we have 4 level-0 files

Stopping writes because we have 20 level-0 files

  • 預計的compaction數據量太多。當預計的compaction數據量到達soft_pending_compaction_bytes時,會寫限速。當預計的compaction數據量到達hard_pending_compaction_bytes時,會寫阻塞,等待compaction。在這種情況下,你可以在LOG文件中查看到大概如下的log:Stalling writes because of estimated pending compaction bytes 500000000

Stopping writes because of estimated pending compaction bytes 1000000000

不管什麼時候觸發了阻寫,RocksDB都會降低寫速度為delayed_write_rate,如果預計的compaction數據量還在不斷的累積,那麼寫入速度降到比delayed_write_rate還要低。有一點值得注意,雖然寫限速/阻塞配置和預計compaction數據量大小配置在每個colum family中,但阻寫是針對整個數據庫的,換句話說就是如果一個column family觸發了阻寫,那麼整個數據庫就會阻寫。

RockDB有許多選項可以用來對阻寫進行調優,這樣可以滿足不同的場景(有的可以接受阻寫,有的則不能)。你可以將某些寫設置為低優先級寫,從而避免阻塞那些對延遲要求較高的寫。

如果阻寫是flush觸發的,你可以試試以下方法:

  • 增大max_background_flushes(增加flush線程)
  • 增大max_write_buffer_number(增大memtable數量,應對突發的大量寫)

如果阻寫是由於level-0層有太多的文件或是預計compaction數據量太大,或是compaction速度趕不上寫入速度。注意,可以通過降低寫放大來減少compaction時需要寫入的數據量,因此可以設置compaction.Option中的以下參數:

  • 增大max_background_compactions(增大compact線程)
  • 增大write_buffer_size(增大memtable,降低寫放大)
  • 增大min_write_buffer_number_to_merge(多少個memtable才會觸發一次flush,比如設置成2,則有兩個immutable memtables時才會flush到磁盤上。如果多個memtable被一次性merge,那麼就會有更少的key寫入磁盤,因為多個memtable中重複的key會被合併)

盤,因為多個memtable中重複的key會被合併)