Ceph的BlueStore總體介紹

整體架構

bluestore的誕生是爲了解決filestore自身維護一套journal並同時還需要基於系統文件系統的寫放大問題,並且filestore本身沒有對SSD進行優化,因此bluestore相比於filestore主要做了兩方面的核心工作:
  • 去掉journal,直接管理裸設備
  • 針對SSD進行單獨優化
bluestore的整體架構如下圖所示:

通過Allocator實現對裸設備的管理,直接將數據保存到設備上;同時針對metadata使用RocksDB進行保存,底層自行封裝了一個BlueFS用來對接RocksDB與裸設備。

模塊劃分

核心模塊

  • RocksDB: 存儲預寫式日誌、數據對象元數據、Ceph的omap數據信息、以及分配器的元數據(分配器負責決定真正的數據應在什麼地方存儲)
  • BlueRocksEnv: 與RocksDB交互的接口
  • BlueFS: 小的文件系統,解決元數據、文件空間及磁盤空間的分配和管理,並實現了rocksdb::Env 接口(存儲RocksDB日誌和sst文件)。因爲rocksdb常規來說是運行在文件系統的頂層,下面是BlueFS。 它是數據存儲後端層,RocksDB的數據和BlueStore中的真正數據被存儲在同一個塊物理設備
  • HDD/SSD: 物理塊設備,存儲實際的數據
rocksdb本身是基於文件系統的,不是直接操作裸設備。它將系統相關的處理抽象成Env,用戶可用實現相應的接口(rocksdb默認的Env是PosixEnv,直接對接本地文件系統)。BlueRocksEnv是bluestore實現的一個類,繼承自rocksdb::EnvWrapper,來爲rocksdb提供底層系統的封裝。

爲了對接BlueRocksEnv,實現了一個小的文件系統BlueFS,只實現rocksdb Env需要的接口。所有的元數據的修改都記錄在BlueFS的日誌中,也就是對於BlueFS,元數據的持久化保存在日誌中。在系統啓動mount這個文件系統時,只需replay日誌,就可將所有的元數據都加載到內存中。BluesFS的數據和日誌文件都通過塊設備保存到裸設備上(BlueFS和BlueStore可以共享裸設備,也可以分別指定不同的設備)。

 bluestore不使用本地文件系統,直接接管裸設備,並且只使用一個原始分區,HDD/SSD所在的物理塊設備實現在用戶態下使用linux aio直接對裸設備進行I/O操作。由於操作系統支持的aio操作只支持directIO,所以對BlockDevice的寫操作直接寫入磁盤,並且需要按照page對齊。其內部有一個aio_thread 線程,用來檢查aio是否完成。其完成後,通過回調函數aio_callback 通知調用方。

緩存模塊

Bluestore實現了自己的緩存機制,定義了structure :OnodeSpace,用來map 到內存中的ONODE;BufferSpace,用來map 塊信息blob,每個blob都在bufferSpace中緩存了狀態數據。二者在緩存中依照LRU的方式決定生命週期。 

FreelistManager模塊

FreelistManager用來映射磁盤的使用信息,最初實現是採用k-v的方式來存儲對應的磁盤塊的使用情況,但是由於更新數據時需要修改映射,需要線程鎖來控制修改,而且這種方式對內存消耗很大;後續修改爲bitmap的映射方式,設定一個offset來以bitmap的方式map多個block使用信息,使用XOR計算來更新塊的使用情況,這種方式不會出現in-memory 狀態。 

Allocator模塊 

用來委派具體哪個實際存儲塊用來存儲當前的object數據;同樣採用bitmap的方式來實現allocator,同時採用層級索引來存儲多種狀態,這種方式對內存的消耗相對較小,平均1TB磁盤需要大概35M左右的ram空間

bluestore元數據

在之前的存儲引擎filestore裏,對象的表現形式是對應到文件系統裏的文件,默認4MB大小的文件,但是在bluestore裏,已經沒有傳統的文件系統,而是自己管理裸盤,因此需要有元數據來管理對象,對應的就是Onode,Onode是常駐內存的數據結構,持久化的時候會以kv的形式存到rocksdb裏。

在onode裏又分爲lextent,表示邏輯的數據塊,用一個map來記錄,一個onode裏會存在多個lextent,lextent通過blob的id對應到blob(bluestore_blob_t ),blob裏通過pextent對應到實際物理盤上的區域(pextent裏就是offset和length來定位物理盤的位置區域)。一個onode裏的多個lextent可能在同一個blob裏,而一個blob也可能對應到多個pextent。
另外還有Bnode這個元數據,它是用來表示多個object可能共享extent,目前在做了快照後寫I/O觸發的cow進行clone的時候會用到。

I/O讀寫映射邏輯

寫I/O處理

到達bluestore的I/O的offset和length都是對象內(onode)的,offset是相對於這個對象起始位置的偏移,在_do_write裏首先就會根據最小分配單位min_alloc_size進行判斷,從而將I/O分爲對齊和非對齊的。當一個寫請求按照min_alloc_size進行拆分後,就會分爲對齊寫,對應到do_write_big,非對齊寫(即落到某一個min_alloc_size區間的寫I/O(對應到do_write_small)。
  • do_write_big
對齊到min_alloc_size的寫請求處理起來比較簡單,有可能是多個min_alloc_size的大小,在處理時會根據實際大小新生成lextent和blob,這個lextent跨越的區域是min_alloc_size的整數倍,如果這段區間是之前寫過的,會將之前的lextent記錄下來便於後續的空間回收。
  • do_write_small
在處理落到某個min_alloc_size區間的寫請求時,會首先根據offset去查找有沒有可以複用的blob,因爲最小分配單元是min_alloc_size,默認64KB,如果一個4KB的寫I/O就只會用到blob的一部分,blob裏剩餘的還能放其他的。

讀I/O的處理

讀I/O請求的處理時也是通過尋找相關聯的lextent,可能會存在空洞的情況,即讀到未寫過的數據,這部分就直接補零。

總結

從BlueStore 的設計和實現上看,可以將其理解爲用戶態下的一個文件系統,同時使用RocksDB來實現BlueStore所有元數據的管理,簡化實現。

​對於整塊數據的寫入,數據直接以aio的方式寫入磁盤,再更新RocksDB中數據對象的元數據,避免了filestore的先寫日誌,後apply到實際磁盤的兩次寫盤。同時避免了日誌元數據的冗餘存儲佔用,因爲傳統文件系統有他們自己內部的日誌和元數據管理機制。

​對於隨機IO,直接WAL的形式,寫入RocksDB 高性能的KV存儲中。

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