Ceph BlueStore:BlockDevice代码详解。

背景

在BlueStore存储引擎中,数据和元数据的存储不再经过操作系统层,OSD直接管理裸盘空间,通过libaio对裸盘进行读写。为了更好的兼容性,BlueStore提供了BlockDevice层作为写盘IO的调度层,也管理不同类型的盘,如HDD、Sata SSD和Nvme SSD。
本文后续基于N版本进行介绍,主要介绍HDD场景,HDD场景BlockDevice会抽象为KernelDevice类。

本文结论

  • Device使用流程为
    • 异步写:aio_write(异步写入队)、aio_submit(遍历队列写盘)、aio_thread(检查写盘完成)
    • 同步写:write(同步写盘)
    • 同步刷盘:flush(同步刷盘)
    • 同步trim:discard(trim)
    • 后台trim:queue_discard(trim extent入队)、discard_thread(执行队列中trim任务)
  • Device设备文件主要有两种(block和block.db),需要在osd创建的时候将本地磁盘软链接到Device设备文件。
    • block:用于存储数据。
    • block.db:用于存储rocksdb的元数据。
  • BlockDevice模块提供块设备文件的访问接口,空间的管理需要上层使用者控制。
  • 异步写的过程是并发执行的,两个相互覆盖的IO,是无法保证顺序性的,需要使用者进行互斥的控制。

代码分析

数据结构

下面只解释部分关键字段

class BlockDevice {
   
    uint64_t size; // 设备总大小
    uint64_t block_size; // 块大小
}

class KernelDevice : public BlockDevice {
   
    std::vector<int> fd_direct, fd_buffered; // 裸设备以direct、buffered两种方式打开的fd
    std::string path; // 设备路径
    bool aio, dio; // 是否启用Libaio
    interval_set<uint64_t> discard_queued; // interval_set是offset+length, discard_queued 存放需要做Discard的Extent。
    interval_set<uint64_t> discard_finishing; // discard_finishing 和 discard_queued 交换值,存放完成Discard的Extent
    
    // Libaio线程,收割完成的事件
    struct AioCompletionThread : public Thread {
   
        KernelDevice *bdev;
        explicit AioCompletionThread(KernelDevice *b) : bdev(b) {
   }
        void *entry() override {
   
            bdev->_aio_thread();
            return NULL;
        }
    } aio_thread;
    
    // Discard线程,用于SSD的Trim
    struct DiscardThread : public Thread {
   
        KernelDevice *bdev;
        explicit DiscardThread(KernelDevice *b) : bdev(b) {
   }
        void *entry() override {
   
            bdev->_discard_thread();
            return NULL;
        }
    } discard_thread;
    
    // 同步IO
    int read(uint64_t off, uint64_t len, bufferlist *pbl, IOContext *ioc,
             bool buffered) override;
    int write(uint64_t off, bufferlist &bl, bool buffered) override;

    // 异步IO
    int aio_read(uint64_t off, uint64_t len, bufferlist *pbl,
                 IOContext *ioc) override;
    int aio_read(uint64_t off, uint64_t len, bufferlist *pbl,
                 IOContext *ioc) override;
    void aio_submit(IOContext *ioc) override;

    // sync数据
    int flush() override;

    // 对SSD指定offset、len的数据做Trim
    int discard(uint64_t offset, uint64_t len) override;
};

打开device

create

BlueFS用户态文件系统会使用BlockDevice存放文件系统的数据,BlueStore也会使用BlockDevice存放object相关的数据,创建BlockDevice的时候,通过工厂函数create,根据不同的设备类型,创建不同的设备。

  • 通过上层调用可以看到创建的块设备有两种,见BlueStore::_minimal_open_bluefs等函数。
    • /pathname/block:用于存放数据。
    • /pathname/block.db:用于存放rocksdb元数据。
  • 设备初始化主要是一种内存的操作,真正的块设备是本地磁盘,存储池创建后可以使用软链接的方式将本地磁盘挂载到block或block.db文件,后续对其读写就是对盘的读写了。
BlockDevice *BlockDevice::create(CephContext* cct, const string& path,
		aio_callback_t cb, void *cbpriv) {
   

	// 通过设备的path,判断出设备的类型
	string type = "kernel";
	char buf[PATH_MAX + 1];
	int r = ::readlink(path.c_str(), buf, sizeof(buf) - 1);
	if (r >= 0) {
   
		buf[r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值