ceph的核心之rocksdb


最近調優及其他工作實在太忙,沒有太多時間寫心得,今天抽空來總結一下階段性成果吧。從一開始的ceph調研、系統調優開始,ceph集群存儲大規模數據之后(集群文件數超過2億),rgw並發寫性能下降的問題一直困擾我們,終於在最近找到了原因及相關解決辦法

問題引入

在測試集群的並發性能的時候,我們注意到,經過系統調優后,集群創建初期,至少,在寫入數據低於1億文件數的時期,集群能夠保持比較好的性能,並發雖然會有不少波動,但是基本能維持到7500ops(cosbench),但是再繼續寫,性能就會出現明顯的暴跌,降低到1500ops左右,這顯然是不可接受的;

我們跟蹤排查后發現,每當性能下降劇烈的時候,往往是磁盤有非常厲害的讀:

集群概況:
  cluster:
    id:     b4136ac5-ad0d-45b9-9f74-7e6a6f6d572c
    health: HEALTH_WARN
            noscrub,nodeep-scrub flag(s) set

  services:
    mon: 1 daemons, quorum ceph-c204
    mgr: ceph-c204(active)
    osd: 24 osds: 24 up, 24 in
         flags noscrub,nodeep-scrub
    rgw: 2 daemons active

  data:
    pools:   6 pools, 2208 pgs
    objects: 201M objects, 48946 GB
    usage:   109 TB used, 39119 GB / 147 TB avail
    pgs:     2208 active+clean

  io:
    client:   11944 kB/s rd, 390 MB/s wr, 11944 op/s rd, 26640 op/s wr
磁盤讀寫情況:
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           6.97    0.05    3.21    3.77    0.00   85.99

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00     6.00    0.00    6.00     0.00    60.00    20.00     0.01    1.00    0.00    1.00   1.00   0.60
sdb               0.00     0.00  105.00 3725.00  3320.00 29008.00    16.88     0.34    0.09    0.54    0.08   0.06  23.70
sde               0.00     0.00    5.00 2111.00    40.00  7084.00     6.73     0.23    0.11    0.60    0.11   0.11  22.60
sdm               0.00     0.00    0.00 1909.00     0.00  6996.00     7.33     0.21    0.11    0.00    0.11   0.11  21.00
sdk               0.00    64.00   16.00  523.00  2184.00 44412.00   172.90     0.67    1.24   13.81    0.86   0.61  32.80
sdh               0.00    67.00   64.00  520.00 10052.00 45028.00   188.63     2.46    4.32   20.00    2.39   0.88  51.10
sdj               0.00    84.00   33.00  596.00  4268.00 50524.00   174.22     1.81    2.75   29.61    1.26   0.88  55.50
sdl               0.00    65.00   54.00  560.00  7832.00 51004.00   191.65     2.07    3.37   20.52    1.72   0.79  48.40
sdd               0.00    75.00   49.00  575.00  7604.00 52504.00   192.65     1.29    1.98   10.96    1.22   0.69  43.00
sdg               0.00    71.00   78.00  512.00 11604.00 46308.00   196.31    24.12   39.48   98.64   30.47   1.69 100.00
sdf               0.00    93.00   21.00  589.00  2820.00 52000.00   179.74     1.49    2.43   37.38    1.18   0.74  45.30
sdi               0.00    80.00  208.00  539.00 47312.00 45628.00   248.84    39.40   49.48   82.35   36.80   1.33  99.70
sdc               0.00    67.00   64.00  539.00  9932.00 47136.00   189.28     2.30    3.68   18.72    1.90   0.99  59.60
sdn               0.00    84.00   39.00  497.00  5592.00 41968.00   177.46     2.15    3.91   27.21    2.09   0.98  52.40

根據觀察,當磁盤有讀操作的時候,寫性能往往會下降很多,使用iotop發現,產生大量讀的線程主要是[rocksdb:bg0]一類的線程,那么這些都是些什么線程,又在做什么讀操作呢?不急,我們先學習一下rocksdb

從LSM-Tree說起

Rocksdb源自於Leveldb,fork了Leveldb的代碼后,facebook在Leveldb的基礎上做了很多的改進,然后開源並重新命名為Rocksdb,leveldb和rocksdb一樣,都是基於LSM-Tree思想所設計的

LSM-TREE

LSM-Tree全稱是Log-Structed-Merge-Tree,是一種數據結構思想,它的理論基礎是,傳統磁盤順序讀寫速度比隨機讀寫速度快得多,因此它想了個辦法:將隨機的讀寫轉換成順序讀寫,從而提高讀寫性能

LSM-Tree的組成結構是:
1、memtable - 常駐內存,主要負責保存要寫入的數據
2、immutable - 當memtable寫滿后,就會變成只讀的immutable
3、wal file - 實現log功能,掉電后用以恢復數據
4、SStable - 持久化存在磁盤中的數據庫文件,保存了所有的數據

注:圖片來自rocksdb detail

這里解釋一下rocksdb的讀寫流程:

寫流程

1、首先,為了保證掉電數據恢復,rocksdb先寫wal中的log文件,注意,這里是追加模式寫,因此速度很快
2、然后寫位於內存中的memtable;
3、客戶端寫返回
4、rocksdb檢查memtable否寫滿,如果寫滿,則memtable變成immutable,只允許讀,等待flush
5、當immutable滿足flush條件后,會將immutable的內容一次性flush到磁盤上,作為level0的sst文件保存在db的磁盤分區中
注意,當memtable的內容flush到磁盤上后,所有level的記錄都是有序的,因此,在memtable flush到磁盤上時,會進行去重和排序

讀流程

1、讀請求首先到達memtable,在memtable中查找,查到即返回,否則繼續查找
2、在level0中查找,因為rocksdb保證了每一個level的所有記錄都是有序的,因此使用二分查找速度很快
3、在上級level中未查到,則需要繼續往下查找,直到最后一個level,若仍未查到,則返回查找失敗,否則,返回第一次查找到的記錄

關於刪除和修改

對於刪除和修改,與寫入並沒有太大的區別,刪除的時候,會寫入一條kv記錄,但是該kv記錄帶有刪除標記,待進行SStable合並的時候,會進行實際的刪除操作,而修改操作也是,寫入一條帶有修改標記的kv記錄,SStable合並的時候會進行對比,保留最新的一條kv記錄。

小總結

LSM-Tree為了提高io性能,將隨機寫進行了合並,使得每次寫操作都能夠在一次磁盤io和內存io后返回,速度很快,並且其規定,刪除和修改也是作為一條操作記錄寫入,在后續才進行實際的刪除和修改

Rocksdb的SST文件合並

LSM-Tree保證了寫操作在一次磁盤和一次內存寫后就能返回,但在leveldb/rocksdb端后續處理上,還是有很多的工作,最重要的就是數據落盤后SST文件的合並處理;對於Leveldb來說,寫入磁盤后的SStable文件會被分成多個不同的level,這也是leveldb名稱的由來;leveldb/rocksdb的組織方式是,當某個level的文件數量或者總大小達到預設的值后,該level的一個文件(level0為所有文件)就會與下一層的文件發生合並,合並后的文件會進入下一個level,例如level0文件大小或數量達到閾值后就會與level1的文件發生合並,原來的level1的文件就可以安全刪除了,當然,在合並的時候會進行去重和排序操作,這樣就能保證每一層的數據都是有序的,此時的排序相當於N路歸並排序。

注:圖片來自Leveled Compaction
上圖可以清楚地看出,memtable刷入磁盤后形成level0的SST文件,而level0會往下合並,最終形成一棵LSM-Tree

關於rocksdb的相關內容就先做個簡單的梳理,網上有非常優秀的資源對其進行了詳細、深入的介紹,尤其是facebook的官方,更是給出了最權威最有價值的資料,對深入學習rocksdb提供了很大的幫助


免責聲明!

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



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