内容简介:Ceph从Luminous开始,默认使用了全新的存储引擎BlueStore,来替代之前提供存储服务的FileStore,与FileStore不一样的是,BlueStore直接管理裸盘,分配数据块来存储RADOS里的objects。Bluestore比较复杂,学习BlueStore的关键就是查看其实现的 ”object → block device“ 映射,所以本文先重点分析下该部分:一个Object写到Bluestore的处理过程。下面借用
Ceph从Luminous开始,默认使用了全新的存储引擎BlueStore,来替代之前提供存储服务的FileStore,与FileStore不一样的是,BlueStore直接管理裸盘,分配数据块来存储RADOS里的objects。
Bluestore比较复杂,学习BlueStore的关键就是查看其实现的 ”object → block device“ 映射,所以本文先重点分析下该部分:一个Object写到Bluestore的处理过程。
Bluestore整体架构
下面借用 Sage Weil 的图描述下BlueStore的整体架构:
里面的几个关键组件介绍:
- RocksDB:存储元数据信息
- BlueRocksEnv:提供RocksDB的访问接口
- BlueFS:实现BlueRocksEnv里的访问接口
- Allocator:磁盘分配器
针对BlueStore的整体架构不做展开,大家只需对其几大组件有些了解即可,本文继续介绍Object写操作到底层BlockDevice的过程。
BlueStore中Object到底层Device的映射关系
这里先从整体上给出在BlueStore中,一个Object的数据映射到底层BlockDevice的实现,如下图:
首先详细介绍下与上诉映射关系相关的数据结构。
Bluestore相关数据结构
BlueStore里与Object 数据映射相关的数据结构罗列如下:
Onode
任何RADOS里的一个Object都对应Bluestore里的一个Onode(内存结构),定义如下:
struct Onode { Collection *c; // 对应的Collection,对应PG ghobject_t oid; // Object信息 bluestore_onode_t onode; // Object存到kv DB的元数据信息 ExtentMap extent_map; // 映射lextents到blobs };
通过Onode里的ExtentMap来查询Object数据到底层的映射。
ExtentMap
ExtentMap
是 Extent
的set集合,是有序的,定义如下:
struct ExtentMap { Onode *onode; // 指向Onode指针 extent_map_t extent_map; // Extents到Blobs的map blob_map_t spanning_blob_map; // 跨越shards的blobs struct Shard { bluestore_onode_t::shard_info *shard_info = nullptr; unsigned extents = 0; ///< count extents in this shard bool loaded = false; ///< true if shard is loaded bool dirty = false; ///< true if shard is dirty and needs reencoding }; mempool::bluestore_cache_other::vector<Shard> shards; ///< shards };
ExtentMap还提供了分片功能,防止在文件碎片化严重,ExtentMap很大时,影响写RocksDB的性能。
ExtentMap
会随着写入数据的变化而变化;
ExtentMap
的连续小段会合并为大;
覆盖写也会导致 ExtentMap
分配新的Blob;
Extent
Extent是实现object的数据映射的关键数据结构,定义如下:
struct Extent : public ExtentBase { uint32_t logical_offset = 0; // 对应Object的逻辑偏移 uint32_t blob_offset = 0; // 对应Blob上的偏移 uint32_t length = 0; // 数据段长度 BlobRef blob; // 指向对应Blob的指针 };
每个Extent都会映射到下一层的Blob上,Extent会依据 block_size 对齐,没写的地方填充全零。
Extent中的 length
值,最小:block_size,最大:max_blob_size
Blob
Blob是Bluestore里引入的处理块设备数据映射的中间层,定义如下:
struct Blob { int16_t id = -1; SharedBlobRef shared_blob; // 共享的blob状态 mutable bluestore_blob_t blob; // blob的元数据 }; struct bluestore_blob_t { PExtentVector extents; // 对应磁盘上的一组数据段 uint32_t logical_length = 0; // blob的原始数据长度 uint32_t compressed_length = 0; // 压缩的数据长度 };
每个Blob会对应一组 PExtentVector,它就是 bluestore_pextent_t 的一个数组,指向从Disk中分配的物理空间。
Blob里可能对应一个磁盘pextent,也可能对应多个pextent;
Blob里的pextent个数最多为:max_blob_size / min_alloc_size;
Blob里的多个pextent映射的Blob offset可能不连续,中间有空洞;
AllocExtent
AllocExtent是管理物理磁盘上的数据段的,定义如下:
struct bluestore_pextent_t : public AllocExtent { ... }; class AllocExtent { public: uint64_t offset; // 磁盘上的物理偏移 uint32_t length; // 数据段的长度 ... };
AllocExtent的 length
值,最小:min_alloc_size,最大:max_blob_size
BlueStore写数据流程
BlueStore里的写数据入口是 BlueStore::_do_write()
,它会根据 min_alloc_size 来切分 [offset, length] 的写,然后分别依据 small write 和 big write 来处理,如下:
// 按照min_alloc_size大小切分,把写数据映射到不同的块上 [offset, length] |==p1==|=======p2=======|=p3=| |----------------|----------------|----------------| | min_alloc_size | min_alloc_size | min_alloc_size | |----------------|----------------|----------------| small write: p1, p3 big write: p2 BlueStore::_do_write() |-- BlueStore::_do_write_data() | // 依据`min_alloc_size`把写切分为`small/big`写 | | -- BlueStore::_do_write_small() | | | -- BlueStore::ExtentMap::seek_lextent() | | | -- BlueStore::Blob::can_reuse_blob() | | reuse blob? or new blob? | | | -- insert to struct WriteContext {}; | | -- BlueStore::_do_write_big() | | | -- BlueStore::ExtentMap::punch_hole() | | | -- BlueStore::Blob::can_reuse_blob() | | reuse blob? or new blob? | | | -- insert to struct WriteContext {}; |-- BlueStore::_do_alloc_write() | | -- StupidAllocator::allocate() | | -- BlueStore::ExtentMap::set_lextent() | | -- BlueStore::_buffer_cache_write() |-- BlueStore::_wctx_finish()
BlueStore Log分析
可以通过开启Ceph bluestore debug来抓取其写过程中对数据的映射,具体步骤如下。
下面通过在CephFS上测试为例:
1. 创建一个文件 # touch tstfile 2. 查看该文件的inode numer # ls -i 2199023255554 tstfile 3. 获取该文件的映射信息 上诉inode number转换为16进制:20000000002 查看文件的第一个默认4M Object的映射信息 # ceph osd map cephfs_data_ssd 20000000002.00000000 osdmap e2649 pool 'cephfs_data_ssd' (3) object '20000000002.00000000' -> pg 3.3ff3fe94 (3.94) -> up ([12,0], p12) acting ([12,0], p12) 4. 在osd 12上开启bluestroe debug信息 # ceph daemon /var/run/ceph/ceph-osd.12.asok config set debug_bluestore "30" // 开启debug # ceph daemon /var/run/ceph/ceph-osd.12.asok config set debug_bluestore "1/5" // 恢复默认 5. 对测试文件的前4M内进行dd操作,收集log # dd if=/dev/zero of=tstfile bs=4k count=1 oflag=direct # grep -v "trim shard target" /var/log/ceph/ceph-osd.12.log | grep -v "collection_list" > bluestore-write-0-4k.log
通过上述方式可以搜集到Bluestore在写入数据时,object的数据分配和映射过程,可以帮助理解其实现。
BlueStore dd write各种case
为了更好的理解BlueStore里一个write的过程,我们通过 dd
命令写一个Object,然后抓取log后分析不同情况下的Object数据块映射情况,最后结果如下图所示:
注释:上图的数据块映射关系是通过抓取log后获取的。
最后一图中,写[100k, 200)的区域,查看Object对应的ExtentMap并不是与 min_alloc_size(16k)对齐的,只是保证是block_size(4k)对齐而已。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。