歡迎光臨
每天分享高質量文章

打造使用者態儲存利器,基於SPDK的儲存引擎Blobstore & BlobFS

作者簡介

周雁波,Intel儲存軟體工程師,主要從事SPDK軟體開發工作。

    Blobstore是位於SPDK bdev之上的Blob管理層,用於與使用者態檔案系統Blobstore Filesystem (BlobFS)整合,從而代替傳統的檔案系統,支援更上層的服務,如資料庫MySQL、K-V儲存引擎Rocksdb以及分散式儲存系統Ceph、Cassandra等。以Rocksdb為例,透過BlobFS作為Rocksdb的儲存後端的優勢在於,I/O經由BlobFS與Blobstore下發到bdev,隨後由SPDK使用者態driver寫入磁碟。整個I/O流從發起到落盤均在使用者態操作,完全bypass核心。此外,可以充分利用SPDK所提供的非同步、無鎖化、Zero Copy、輪詢等機制,大幅度減少額外的系統開銷。它們之間的關係如下所示(以NVMe bdev為例):

    BlobFS在管理檔案時,主要依賴於Blobstore對blob的分配與管理。Blob類似於檔案的概念,而又不完全等同於檔案,其並不支援所有檔案的POSIX介面。BlobFS與Blobstore的關係可以理解為Blobstore實現了對Blob的管理,包括Blob的分配、刪除、讀取、寫入、元資料的管理等,而BlobFS是在Blobstore的基礎上進行封裝的一個輕量級檔案系統,用於提供部分對於檔案操作的介面,並將對檔案的操作轉換為對Blob的操作,BlobFS中的檔案與Blobstore中的Blob一一對應。在Blobstore下層,與SPDK bdev層對接。SPDK bdev層類似於核心中的通用塊裝置層,是對底層不同型別裝置的統一抽象管理,例如NVMe bdev、Malloc bdev、AIO bdev等。

Blobstore中結構的劃分

    在blobstore中,將SSD中的塊劃分為多個抽象層,主要由Logical Block、Page、Cluster、Blob組成,它們之間的關係如下所示:

  • Logical Block:與塊裝置中所提供的邏輯塊相對應,通常為512B或4KiB。

  • Page:由多個連續的Logical Block構成,通常一個page的大小為4KiB,因此一個Page由八個或一個Logical Block構成,取決於Logical Block的大小。在Blobstore中,Page是連續的,即從SSD的LBA 0開始,多個或一個塊構成Page 0,接下來是Page 1,依次類推。

  • Cluster:由多個連續的Page構成,通常一個Cluster的大小預設為1MiB,因此一個Cluster由256個Page構成。Cluster與Page一樣,是連續的,即從SSD的LBA 0開始的位置依次為Cluster 0到Cluster N。

  • Blob:Blobstore中主要的操作物件為Blob,與BlobFS中的檔案相對應,提供read、write、create、delete等操作。一個Blob由多個Cluster構成,但構成Blob中的Cluster並不一定是連續的。

那麼Blobstore是如何管理塊的分配呢?

    在Blobstore中,會將cluster 0作為一個特殊的cluster。該cluster用於存放Blobtore的所有資訊以及元資料,對每個blob資料塊的查詢、分配都是依賴cluster 0中所記錄的元資料所進行的。Cluster 0的結構如下:

    Cluster 0中的第一個page作為super block,Blobstore初始化後的一些基本資訊都存放在super block中,例如cluster的大小、已使用page的起始位置、已使用page的個數、已使用cluster的起始位置、已使用cluster的個數、Blobstore的大小等資訊。

    Cluster 0中的其它page將組成元資料域(metadata region)。元資料域主要由以下幾部分組成:

  • Metadata Page Allocation:用於記錄所有元資料頁的分配情況。在分配或釋放元資料頁後,將會對metadata page allocation中的資料做相應的修改。

  • Cluster Allocation:用於記錄所有cluster的分配情況。在分配新的cluster或釋放cluster後會對cluster allocation中的資料做相應的修改。

  • Blob Id Allocation:用於記錄blob id的分配情況。對於blobstore中的所有blob,都是透過唯一的識別符號blob id將其對應起來。在元資料域中,將會在blob allocation中記錄所有的blob id分配情況。

  • Metadata Pages Region:元資料頁區域中存放著每個blob的元資料頁。每個blob中所分配的cluster都會記錄在該blob的元資料頁中,在讀寫blob時,首先會透過blob id定位到該blob的元資料頁,其次根據元資料頁中所記錄的資訊,檢索到對應的cluster。對於每個blob的元資料頁,並不是連續的。

    對於一個blob來說,metadata page記錄了該blob的所有資訊,資料存放於分配給該blob的cluster中。在建立blob時,首先會為其分配blob id以及metadata page,其次更新metadata region。當對blob進行寫入時,首先會為其分配cluster,其次更新該blob的metadata page,最後將資料寫入,並持久化到磁碟中。

    為了實現對磁碟空間的動態分配管理,Blobstore中為每個blob分配的cluster並不是連續的。對於每個blob,透過相應的結構維護當前使用的cluster以及metadata page的資訊:clusters與pages。Cluster中記錄了當前該blob所有cluster的LBA起始地址,pages中記錄了當前該blob所有metadata page的LBA起始地址。

    Blobstore實現了對磁碟空間分配的動態管理,並保證斷電不丟失資料,因此Blob具有persistent特性。Blobstore中的配置資訊與資料資訊均在super block與metadata region中管理,在重啟後,若要保持persistent,可以透過Blobstore中所提供的load操作。

註意:

Blob的persistent主要是針對NVMe這類bdev。對於Malloc bdev,由於其本身的性質,是無法保證Blob的persistent,需要重啟後進行重新配置。

    下麵透過檔案的讀寫來講解BlobFS與Blobstore中的I/O流程:

    檔案讀取:檔案讀取操作的流程圖如下所示:

    為了提高檔案的讀取效率,BlobFS在記憶體中提供了cache buffer。在檔案讀寫時,首先會進行read ahead操作,將一部分資料從磁碟預先讀取到記憶體的buffer中。其後,根據cache buffer的大小,對檔案的I/O進行切分,使每個I/O的最大長度不超過一個cache buffer的大小。對於拆分後的檔案I/O,會根據其offset在cache buffer tree中查詢相應的buffer。若存在,則直接從cache buffer中讀取資料,進行memcpy。而對於沒有快取到cache buffer中的資料,將會對該檔案的讀取,轉換到該檔案對應的Blob進行讀取。對Blob讀取時候,根據已開啟的blob結構中記錄的資訊,可以獲取該blob所有cluster的LBA起始位置,並根據讀取位置的offset資訊,計算相應的LBA地址。最後向SPDK bdev層傳送非同步的讀請求,並等待I/O完成。BlobFS所提供的讀操作為同步讀,I/O完成後會在callback函式中,透過訊號量通知BlobFS完成訊號,至此檔案讀取結束。

    對於cache buffer tree,其結構如下所示:

    Cache buffer tree是由多層樹結構組成。最底層Level 0葉子節點為buffer node,是用於存放資料的buffer。Level 0以上的其它層中,均為tree node,用於構建樹的索引結構。在檔案讀寫的時候,根據檔案結構中的根節點以及讀取位置的offset資訊,在樹結構中透過索引查詢buffer node的位置,即從Level N,逐步定位到對應的Level 0的葉子節點。

    檔案寫入:檔案寫入操作的流程圖如下所示:

    BlobFS目前用於支援上層的Rocksdb,在Rocksdb的抽象環境層中提供檔案的介面,目前僅支援append型別的寫操作。在進行檔案寫入時,首先會根據檔案當前的寫入位置檢查是否符合cache buffer寫入需求,若滿足,則直接將資料寫入到cache buffer中,同時觸發非同步的flush操作。在flush的過程中,BlobFS觸發Blob的寫操作,將cache buffer中的資料,寫入到檔案對應blob的相應位置。若不滿足cache buffer的寫入需求,BlobFS則直接觸發檔案對應的blob的寫操作。Blobstore首先為該blob分配cluster,根據計算得到的寫入LBA資訊,向SPDK bdev層傳送非同步的寫請求,將資料寫入,並更新相應的元資料。對於元資料的更新,出於效能考慮,當前對元資料的更新都在記憶體中操作,當使用者使用強制同步或解除安裝Blobstore時,更新後的元資料資訊才會同步到磁碟中。此外,blob結構中維護了兩份可變資訊(指cluster與metadata page)的元資料,分別為clean與active。Clean中記錄的是當前磁碟的元資料資訊,而active中記錄的是當前在記憶體中更新後的元資料資訊。同步操作會將clean中記錄的資訊與active記錄的資訊相匹配。

總結

    Blobstore實現對Blob管理,Blob類似與檔案的概念,但又不完全等同於檔案,Blob沒有完全遵循檔案的POSIX介面,因此避免與檔案混淆,在SPDK中稱之為Blob而不是File。Blobstore Filesystem (BlobFS)是基於Blobstore實現的輕量級檔案系統,對Blobstore進行封裝,提供一些檔案的常用介面,如read、write、open、sync等,其目的在於作為檔案系統支援更上層的應用,例如Rocksdb。但其本質仍然是Blobstore,因此命名為BlobFS。目前SPDK基於維護了Rocksdb的一個分支,該分支下的Rocksdb在環境抽象層主要透過BlobFS進行對接,I/O可以經由BlobFS繞過核心I/O棧。關於Rocksdb的搭建與測試步驟,可以參考[3]。

參考連結:

[1] https://spdk.io

[2] https://github.com/spdk/spdk

[3] https://spdk.io/doc/blobfs.html

文章轉自公眾號“DPDK與SPDK開源社群”

贊(0)

分享創造快樂