RocksDB有一個(gè)廣泛使用的功能就是當(dāng)flush或compact速度小于外部數(shù)據(jù)寫(xiě)入速度的時(shí)候可以阻寫(xiě)。如果沒(méi)有這個(gè)功能的話,那么當(dāng)用戶持續(xù)寫(xiě)入的數(shù)據(jù)超過(guò)磁盤(pán)所能處理的數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)就會(huì)出現(xiàn)以下情況:
- 空間放大,導(dǎo)致磁盤(pán)寫(xiě)滿(compact來(lái)不及刪除冗余數(shù)據(jù));
- 讀放大,嚴(yán)重降低讀性能(冗余數(shù)據(jù)來(lái)不及刪除導(dǎo)致讀遍歷的sst文件數(shù)量變多)。
解決上述問(wèn)題的方法就是將寫(xiě)入速度降低到數(shù)據(jù)庫(kù)可以正常處理的速度。有時(shí)候數(shù)據(jù)庫(kù)會(huì)面臨突發(fā)的大量寫(xiě)請(qǐng)求,或者硬件處理速度比較慢(比如機(jī)械硬盤(pán)),這時(shí)你在訪問(wèn)數(shù)據(jù)庫(kù)時(shí)就可能出現(xiàn)意想不到的緩慢或查詢超時(shí)。
可以通過(guò)以下方法來(lái)判斷你的DB是否存在阻寫(xiě)問(wèn)題:
- 查看LOG文件,看是否有阻寫(xiě)的log輸出;
-
查看LOG文件的Compatction狀態(tài),如下圖:
compact_stats.png
以下原因可能會(huì)導(dǎo)致阻寫(xiě):
- memtable太多。當(dāng)需要flush的memtable數(shù)量大于等于max_write_buffer_number時(shí),會(huì)寫(xiě)阻塞,直到memtable flush完成。另外,如果max_write_buffer_number大于3,并且待flush的memtable大于等于max_write_buffer_number - 1時(shí),寫(xiě)限速。在這種情況下,你可以在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文件太多。當(dāng)level-0層的文件數(shù)量到達(dá)level0_slowdown_writes_trigger時(shí),會(huì)寫(xiě)限速。當(dāng)level-0層的文件數(shù)量到達(dá)level0_stop_writes_trigger時(shí),會(huì)寫(xiě)阻塞,直到level-0層的SST文件合并到level-1層,使level-0層的文件數(shù)目減少。在這種情況下,你可以在LOG文件中查看到大概如下的log:
Stalling writes because we have 4 level-0 files
Stopping writes because we have 20 level-0 files
- 預(yù)計(jì)的compaction數(shù)據(jù)量太多。當(dāng)預(yù)計(jì)的compaction數(shù)據(jù)量到達(dá)soft_pending_compaction_bytes時(shí),會(huì)寫(xiě)限速。當(dāng)預(yù)計(jì)的compaction數(shù)據(jù)量到達(dá)hard_pending_compaction_bytes時(shí),會(huì)寫(xiě)阻塞,等待compaction。在這種情況下,你可以在LOG文件中查看到大概如下的log:
Stalling writes because of estimated pending compaction bytes 500000000
Stopping writes because of estimated pending compaction bytes 1000000000
不管什么時(shí)候觸發(fā)了阻寫(xiě),RocksDB都會(huì)降低寫(xiě)速度為delayed_write_rate,如果預(yù)計(jì)的compaction數(shù)據(jù)量還在不斷的累積,那么寫(xiě)入速度降到比delayed_write_rate還要低。有一點(diǎn)值得注意,雖然寫(xiě)限速/阻塞配置和預(yù)計(jì)compaction數(shù)據(jù)量大小配置在每個(gè)colum family中,但阻寫(xiě)是針對(duì)整個(gè)數(shù)據(jù)庫(kù)的,換句話說(shuō)就是如果一個(gè)column family觸發(fā)了阻寫(xiě),那么整個(gè)數(shù)據(jù)庫(kù)就會(huì)阻寫(xiě)。
RockDB有許多選項(xiàng)可以用來(lái)對(duì)阻寫(xiě)進(jìn)行調(diào)優(yōu),這樣可以滿足不同的場(chǎng)景(有的可以接受阻寫(xiě),有的則不能)。你可以將某些寫(xiě)設(shè)置為低優(yōu)先級(jí)寫(xiě),從而避免阻塞那些對(duì)延遲要求較高的寫(xiě)。
如果阻寫(xiě)是flush觸發(fā)的,你可以試試以下方法:
- 增大max_background_flushes(增加flush線程)
- 增大max_write_buffer_number(增大memtable數(shù)量,應(yīng)對(duì)突發(fā)的大量寫(xiě))
如果阻寫(xiě)是由于level-0層有太多的文件或是預(yù)計(jì)compaction數(shù)據(jù)量太大,或是compaction速度趕不上寫(xiě)入速度。注意,可以通過(guò)降低寫(xiě)放大來(lái)減少compaction時(shí)需要寫(xiě)入的數(shù)據(jù)量,因此可以設(shè)置compaction.Option中的以下參數(shù):
- 增大max_background_compactions(增大compact線程)
- 增大write_buffer_size(增大memtable,降低寫(xiě)放大)
- 增大min_write_buffer_number_to_merge(多少個(gè)memtable才會(huì)觸發(fā)一次flush,比如設(shè)置成2,則有兩個(gè)immutable memtables時(shí)才會(huì)flush到磁盤(pán)上。如果多個(gè)memtable被一次性merge,那么就會(huì)有更少的key寫(xiě)入磁盤(pán),因?yàn)槎鄠€(gè)memtable中重復(fù)的key會(huì)被合并)
