ceph存儲 ceph Bluestore的架構


ceph 目前是開源社區比較流行的分布式塊存儲系統,其以良好的架構,穩定性和完善的數據服務功能,獲得的了廣泛的部署和應用。

目前ceph 最大的問題是其性能相對較差,特別是無法發揮SSD等高速設備的硬件的性能。 Ceph 開源社區一直在優化ceph的性能問題。 目前的結果就是引入了新的object store,這就是最進合並入ceph master的BlueStore.

Bluestore的架構

 

如上圖所示 :

BlueStore整體架構分為四個部分:

  • BlockDevice為最底層的塊設備,BlueStore直接操作塊設備,拋棄了XFS等本地文件系統。BlockDevice在用戶態直接以linux系統實現的AIO直接操作塊設備文件。
  • BlueFS是一個小的文件系統,其文件系統的文件和目錄的元數據都保存在全部緩存在內存中,持久化保存在文件系統的日志文件中, 當文件系統重新mount時,重新replay該直接,就可以加載所有的元數據到內存中。其數據和日志文件都直接保存在依賴低層的BlockDevice中
  • RocksDB 是Facebook在leveldb上開發並優化的KV存儲系統。BlueFS的主要的目的,就是支持RocksDB
  • BlueStore是最終基於RocksDB和BlockDevice實現的ceph的對象存儲,其所有的元數據都保存在RocksDB這個KV存儲系統中,包括collection,對象,omap,磁盤空間分配記錄等都保存RocksDB里, 其對象的數據直接保存在BlockDevice

BlockDevice

BlockDevice 塊設備,其對於一個物理塊設備(目前也支持用XFS的一個大文件里實現),用來存儲實際的數據。其實現在bluestore/BlockDevice.cc 和 bluestore/BlockDevice.h

其主要實現了異步寫操作,寫操作是通過 操作系統提供的異步io調用。 由於操作系統支持的aio操作只支持directIO,所以對BlockDevice的寫操作直接寫入磁盤,並且需要按照page對齊。其內部有一個aio_thread 線程,用來檢查aio是否完成。其完成后,調用 aio_callback_t aio_callback; 回調函數通知調用方。 
目前BlocekDevice的讀操作是同步讀操作。 有待繼續實現異步的讀操作

BlueFS

BlueFs 既然是一個文件系統,就要解決的是元數據的分配管理,其次解決文件空間的分配和管理,以及磁盤空間的分配和管理。

由於BlueFS用來支持RocksDB,所以就不是一個通用的文件系統,它的功能足以支持RocksDB 就可以了。所以它只支持以下功能:

  • 文件只支持順序寫
  • 只支持兩層目錄

BlueFS的元數據

BlueFS中,文件的元數據由 bluefs_fnode_t 保存

struct bluefs_fnode_t {
  uint64_t ino;  //文件的ino uint64_t size; //文件大小 utime_t mtime; // 修改時間 uint8_t prefer_bdev; //優先在該設備上分配空間 vector<bluefs_extent_t> extents; //文件在磁盤上分配的空間 ...... } bluefs_extents_t 代表在磁盤上的分配的extents struct bluefs_extent_t { uint64_t offset; //塊設備上的 extent偏移量 uint32_t length; // extent的長度 uint16_t bdev; //對於的塊設備 ...... }

目錄對應的結構 Dir

struct Dir {
    map<string,FileRef> file_map; };

對於BlueFS

  • 所有的元數據(文件和目錄)都需要緩存在內存中
  • 所有的元數據的修改都記錄在BlueFS的日志中,也就是對於BlueFS,元數據的持久化保存在日志中,當重新mount文件系統時,只需要replay日志,就可以獲取所有元數據
//BlueFS的元數據cache
map<string, Dir*> dir_map; ///< dirname -> Dir ceph::unordered_map<uint64_t,FileRef> file_map; ///< ino -> File

BlueFS的讀寫

uint64_t size = 1048476 * 128; string fn = get_temp_bdev(size); BlueFS fs; ASSERT_EQ(0, fs.add_block_device(0, fn)); fs.add_block_extent(0, 1048576, size - 1048576); uuid_d fsid; ASSERT_EQ(0, fs.mkfs(fsid)); ASSERT_EQ(0, fs.mount()); { BlueFS::FileWriter *h; ASSERT_EQ(0, fs.mkdir("dir")); ASSERT_EQ(0, fs.open_for_write("dir", "file", &h, false)); bufferlist bl; bl.append("foo"); h->append(bl); bl.append("bar"); h->append(bl); bl.append("baz"); h->append(bl); fs.fsync(h); fs.close_writer(h); } { BlueFS::FileReader *h; ASSERT_EQ(0, fs.open_for_read("dir", "file", &h)); bufferlist bl; BlueFS::FileReaderBuffer buf(4096); ASSERT_EQ(9, fs.read(h, &buf, 0, 1024, &bl, NULL)); ASSERT_EQ(0, strncmp("foobarbaz", bl.c_str(), 9)); delete h; } fs.umount();

上述代碼來自test_bluefs.cc的BlueFS的測試代碼,展示了 BlueFS文件系統的使用。

  1. 文件系統調用函數fs.add_block_device 來添加設備到BlueFS中。 
    • 創建了以新的BlockDevice
    • 把該設備添加到bdev列表中,並添加相應的IOContext 到ioc中
  2. 調用 fs.add_block_extent把設備的空間添加到bluefs中
  3. 調用函數fs.mkdir創建目錄
  4. 調用函數 fs.open_for_write 打開一個文件,如果不存在,就創建
  5. 調用h->append 寫數據,目前數據都只是Cache在內存zhong
  6. 最后調用 fs.fsync,本函數真正的把bluefs的 數據和元數據寫入磁盤

RocksDB on BlueFS

如何在BlueFS上實現RocksDB? 對RocksDB, 只要實現 rocksdb::EnvWrapper接口即可。BlueRocksEnv.cc 和 BlueRocksEnv.h 實現了class BlueRocksEnv 來完成此工作。

Bluestore 實現

BlueStore的元數據

Bluestore的 所有的元數據都以KV對的形式寫入RocksDB中,主要有以下的元數據

  1. 保存BlueStore的超級塊信息,在KV中, 以PREFIX_SUPER為Key的前綴 
    const string PREFIX_SUPER = “S”; // field -> value
  2. 保存Collection的元數據信息bluestore_cnode_t 
    const string PREFIX_COLL = “C”; // collection name -> cnode_t
  3. 保存對象的元數據信息 
    const string PREFIX_OBJ = “O”; // object name -> onode_t

    需要主要的是,onode 和 enode的信息 都 以PREFIX_OBJ 為前綴,只是同一個對象的onode和 enode的信息的key不同來區分。

  4. 保存 overly 信息 
    const string PREFIX_OVERLAY = “V”; // u64 + offset -> data

  5. 保存對象的omap 信息 
    const string PREFIX_OMAP = “M”; // u64 + keyname -> value

  6. 保存 write ahead log 信息 
    const string PREFIX_WAL = “L”; // id -> wal_transaction_t

  7. 保存塊設備的空閑extent信息 
    const string PREFIX_ALLOC = “B”; // u64 offset -> u64 length (freelist)

onode 
數據結構onode 保存了BlueStore中一個對象的數據結構,字段和Filestore差不多,這里就不詳細介紹。 
Enode 
數據結構Enode定義了一個共享的extent,也就是這段數據被多個對象共享,一個對象的onode里保存一個enode數據結構,記錄該對象被共享的extent.這個shared extent 用來對象基於extent的Copy-on-write 機制

struct Enode : public boost::intrusive::unordered_set_base_hook<> { atomic_t nref; //< reference count uint32_t hash; string key; //< key under PREFIX_OBJ where we are stored EnodeSet *enode_set; //< reference to the containing set bluestore_extent_ref_map_t ref_map; boost::intrusive::unordered_set_member_hook<> map_item;

數據結構bluestore_extent_ref_map_t 定義了shared extent 被哪些對象引用

struct bluestore_extent_ref_map_t {
  struct record_t { uint32_t length; uint32_t refs; ...... }; ...... map<uint64_t,record_t> ref_map; }

BlueStore的數據讀寫

Bluestore的數據寫入分為兩類:

  1. 數據是整塊覆蓋寫,也就是min_alloc_size對齊的寫入。對於這一類寫入: 
    • 重新分配新的存儲空間
    • 把數據寫入新分配存儲空間
    • 刪除舊的存儲空間
  2. partial write,在這種情況下,部分塊的寫入,在這種情況下: 
    • overly write
    • wal write 
      這種兩種方式都是先把數據寫入 KV 存儲中,后續再apply到實際的存儲空間中,不同之處在於觸發條件不同。

總結

BlueStore 其實是實現了用戶態的一個文件系統。為了實現簡單,又使用了RocksDB來實現了BlueStore的 所有的元數據的管理,簡化了實現。

優點在於:

    • 對於整塊數據的寫入,數據直接aio的方式寫入磁盤,避免了filestore的先寫日志,后apply到實際磁盤的兩次寫盤。
    • 對於隨機IO,直接WAL的形式,直接寫入RocksDB 高性能的KV存儲中

      http://www.cnblogs.com/lucas-sre/p/7096856.html

      ceph后端支持多種存儲引擎,以插件式的方式來進行管理使用,目前支持filestore,kvstore,memstore以及最新的bluestore,目前默認使用的filestore

      Ceph OSD從filestore 轉換到 bluestore的方法


免責聲明!

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



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