❶ BlueStore 架構及原理分析
Ceph 底層存儲引擎經過了數次變遷,目前最常用的是 BlueStore,在 Jewel 版本中引入,用來取代 FileStore。與 FileStore 相比,Bluesore 越過本地文件系統,直接操控裸盤設備,使得 I/O 路徑大大縮短,提高了數據讀寫效率。並且,BlueStore 在設計之初就是針對固態存儲,對目前主力的 SATA SSD 有著更好的支持(相比 FileStore),同時也支持 Nvme SSD 超高速固態。在數據的處理上,BlueStore 選擇把元數據和對象數據分開存儲,使用高速設備來保存元數據,能夠起到性能優化作用。
書中介紹了塊、COW、RWM 等內容,這里也直接拿來主義。
基於以上設計,BlueStore 的寫策略綜合運用直接寫、COW 和 RMW 策略。
注意:
再結合圖1.1 ceph_bluestore 架構圖,我們需要引入第二層觀念:
Ceph 較新版本中,把 設備 模塊單獨放到 blk 文件夾中。
後續還有 pmem、spdk、zoned 設備,這里不再列出
aio 封裝了 lio 相關操作,具體有三個結構:
• aio_t:一次 io 操作,pwrite,pread,不寫到磁碟
• io_queue_t:io 提交隊列,基本不使用,只用作基類
• aio_queue_t:繼承自 io_queue_t,提交 io 操作,真正在此寫入磁碟
簡單介紹 ceph 中 lio 使用流程:
相關方法有:
init():初始化
shutdown():關閉
pwritev():預備寫,後續通過 submit_batch() 完成實際寫入磁碟操作
preadv():預備讀,後續通過 submit_batch() 完成實際寫入磁碟操作
submit_batch():按批次提交 io 任務
get_next_completed():獲取已經完成 IO 的 aio_t,用於 aio_thread() 回調函數
BlockDevice 是所有塊設備的基類,定義了塊設備必備的一些介面,比如 read、write等。在 src/blk/BlockDevice.h 中還定義了 IOContext,用作封裝傳遞 io 具體操作,其中保存著每次 aio 操作的list:pending_aios 和 running_aios,前者表示等待隊列,後者表示正在 io 操作的隊列,同時還創建兩個原子數分別用於表示這兩個隊列中 aio_t 的數量。
BlockDevice提供創建塊設備實例的介面,通過識別 device_type 來創建不同的塊設備,如 kernel device。
BlockDevice BlockDevice::create(
CephContext cct, const string& path, aio_callback_t cb,
void *cbpriv, aio_callback_t d_cb, void *d_cbpriv);
->
create_with_type(device_type, cct, path, cb, cbpriv, d_cb, d_cbpriv);
-> 根據類型創建 device
new KernelDevice(cct, cb, cbpriv, d_cb, d_cbpriv)
-> 創建以下線程
aio_thread:
discard_thread
aio_thread :作用1. 感知已經完成的 io。2. 喚醒等待的 io 或者調用回調函數,具體根據IOContext創建時是否提供了 priv 參數(BlueStore 指針)來決定使用哪種操作,如果提供了,則調用回調函數BlueStore::TransContext::aio_finish()或者BlueStore::DeferredBatch::aio_finish()(根據AioContext 類型)。
discard_thread :這是針對 SSD discard 操作的線程,可以通過 cat /sys/block/sda/queue/discard_granularity 命令查看設備是否支持 discard 操作。discard 在 bluestore 中 分為兩步:第一步:BlkDev{fd_directs[WRITE_LIFE_NOT_SET]}.discard((int64_t) offset, (int64_t) len); 調用系統函數對指定位置做 discard。第二步:discard_callback() 回調 shared_alloc.a->release(),告訴 Allocater 需要回收的部分(標記為 free)。
mkfs 作用是在磁碟第一次使用 bluestore 時,寫入一些用戶指定的配置到磁碟第一個塊——超級塊(大小可配置,一般為: BDEV_LABEL_BLOCK_SIZE 4096),這樣後續使用該磁碟時,可以直接讀取配置項。 之所以需要固化這些配置項,是因為 bluestore 使用不同的配置項對於磁碟數據的組織形式不同,如果前後兩次上電使用不同的配置項訪問磁碟數據有可能導致數據發生永久損壞。對已經 mkfs 過的磁碟再次使用該函數,則會對磁碟做一次 meta 數據檢查。
以下為 LABEL_BLOCK 塊中存儲的數據,主要有 osd id、設備大小、生日時間、設備描述以及一組元數據 map。
mkfs() 主要是初始化 bluestore_bdev_label_t,並寫入到磁碟的第一個4K塊中,同時建立塊設備鏈並預分配指定大小的空間。同時BlueStore層次的mkfs()裡面調用了Bluefs的Bluefs::mkfs(),並且也固化了bluefs的信息位於磁碟的第二個4K塊。
以下給出mkfs詳細步驟。
開啟塊設備。此函數用於創建block設備實例(slow設備),並初始化某些配置。WAL和DB設備由BlueFS自行管理,不在此處開啟。
BlockDevice:create()函數在2.2節中詳細介紹過了,主要作用是打開塊設備,獲取句柄,用於後續的數據讀寫操作。
discard用於SSD設備的空間回收,其作用在2.2節中介紹過。
_set_max_defer_interval()設置了max_defer_interval參數,此參數的作用是在MempoolThread線程中定時提交延遲寫(try->deferred_try_submit()),默認為3。
set_cache_size()從配置中獲取所有cache相關的參數,包括cache總空間,onode內存使用比率、kvdb內存使用比率、hdd、ssd內存使用比率等。