图解Ceph_005_BlueStore空间分配与空闲空间管理

CEPH VERSION: Quincy 17.2.6

上一篇分析了BlueStore的各工作线程,在提交线程中经历了一个比较复杂且重要的过程_txc_add_transaction,它完成了从上层ObjectStore::Transaction到BlueStore::TransContext的转换,转换过程中,对于数据变更类的Op,进行了空间的分配和回收操作,这些操作作为kv事务的一部分被原子提交到RocksDB。

本篇来探究这些数据分配、释放过程的细节,探究Allocator的演变过程,理解开发者们在这个问题上所做的诸多努力。

BlueStore中,空间管理分为两个部分:FreelistManager和Allocator,后续简称为fm和alloc。fm用于表示空闲空间的存储结构以及分配、释放空间的存储数据变更策略,它更贴近于空闲空间的物理存储层面;alloc则侧重于内存表示,它着重于空闲空间快速查找与标记的时间复杂度,和在内存占用的空间复杂度上寻求平衡。

在BlueFS中也使用Allocator,但不使用fm,这是没有办法的事情,fm依赖rocksdb保存其freelist信息,BlueFS作为rocksdb的载体,自然不能再依赖fm,否则就形成了环形依赖,所以BlueFS有自己的空闲空间信息存盘机制。

fm一直以来都使用一个实现BitmapFreelistManager,新的版本增加了ZonedFreelistManager,用于支持SMR Device。由于ZonedFreelistManager比较特殊,下面着重讨论更普遍的BitmapFreelistManager。

image.png

BlueStore::_open_fm函数调用会触发fm的创建或加载,若是创建流程,函数第一个参数会传入一个KeyValueDB::Transaction t事务对象,fm的一系列初始化kv将附加到此事务,附加的kv如下:

prefix db CF Key Value 说明
S freelist_type bitmap或null或zoned 记录所使用的的fm类型
B bytes_per_block 512或4K 设备的Block Size
B blocks_per_key 默认128 每个bitmap key对应多少个block,意味着每个value多少个bit,每个bit对应一个block
B blocks 总block数量 总block数量
B size 设备总空间 设备总空间
b 0 二进制总128bit 11000000...000 Block Size以4K为例 预留8K给label + superblock
  • S - BlueStore的全局元数据prefix
  • B - fm的元数据prefix
  • b - fm的bitmap记录prefix

伴随着fm->allocate的新空间分配,会产生越来越多的b前缀的kv记录

伴随着fm->release的释放操作,原先某个n前缀记录中,Value对应的bit被翻转为0

而fm->allocate的重新分配,又将这些bit翻转为1

所以,allocate和release操作就被统一了,二者都是将offset~length这个区间涉及的对应bit做位翻转(xor)即可。原先没有记录的位置,默认为全0 bit,首次被分配时产生对应kv。

allocate和release操作并不直接修改DB中的kv,而是将kv变更附加到传入的KeyValueDB::Transaction t事务,伴随其余的kv变更一起做原子提交,所以,fm仅仅是提供了allocate和release的kv变更策略。

注意,在新的版本,除了前面创建fm时会将fm meta写到RocksDB外,还会在block设备上的0-4K位置,以bdev label形式记录一份,当然fm的meta只是bdev label的一部分kv。这样做相当于在不同设备不同位置做了super meta的双重备份。

在了解了fm之后,再来看Allocator的实现


image.png

最早使用StupidAllocator,它使用10个bin组成free vector,每个bin是一个interval_set,其中管理着一个btree。每一层的bin管理连续N个free Block的集合,跟Linux的Slab管理有些相似。free[0]的btree中,管理着1个Block的空闲区间;free[1]管理着2个Block的空闲空间;free[2]管理4个Block的空间;...;free[8]管理着256个Block的空间,free[9]则管理着512个及以上的Block的空间。

当需要分配空间时,根据待分配的len找到合适的bin予以分配,分配后可能引起某些区间长度减少,从而需要移动到更低的bin。移动到更低的bin有可能引起合并,合并后又可能移动到更高的bin,然后有可能再次引起合并...

释放空间也是如此,有可能引起分区合并,从而移动到新的bin,移动又可能引发合并,再次移动...

所以,StupidAllocator对于碎片化严重的情况,会有些尴尬,分配、释放可能引起很多额外的操作,性能会变差。

N版本实现的新版BitmapAllocator,详见 https://github.com/ceph/ceph/pull/21825

这个版本的BitmapAllocator相对于老版本,大大提高了空闲空间的lookup效率,其原因在于它做了三层lookup设计:借一张图


image.png

先从L2查找为1的bit,表示其中可能有空闲,然后从L1中找01或11的,再从它们对应的L0中找为1的bit,这样就快速找到空闲的Block。这样的查找过程还能保证连续的多次分配能够找到尽可能相邻的空闲Block,而内存中也能使用尽可能相邻的bits,大大提高了CPU Cache的命中率,进步一提高了分配效率(比较浅显的理解~)。
这个版本解决了老版本的查找效率问题,成为了N版本之后的默认Allocator。

P版新AvlAllocator
Avl allocator中维护了两棵avl树,它们包含了相同的节点,但是排序方式不同。range_tree以offset排序,而range_size_tree以空闲分段的长度排序(使用
oost::intrusive::avl_multiset,允许重复的key值)。

在分配空间时,先根据range_size_tree找到能满足分配长度的最小空闲分区,得到其offset,然后根据offset在range_tree中删除一个[startoffset, startoffset+length]对应的range,这个range涉及节点的分区记录,即为被分配的区间,用它们构造PExtent。

这样两次查找,然后在AVL树上删除一个或连续多个节点(触发AVL树重平衡),以完成分配过程。

释放空间过程则是在两颗树上插入新节点。

boost::intrusive是C++的侵入式容器,相比STL容器有更好的查询性能,它与对象生命周期独立,所以节点对象的生命周期管理会更加复杂。这相当于用实现复杂度来换更好的性能了。

Avl allocator具有Stupid Allocator一样好甚至更好的lookup效率,又避免了在碎片化程度高时的额外合并、移动操作。唯一缺点是,当空闲分区节点数量庞大时,其内存占用量会很大,特别是硬盘容量巨大时。

Avl allocator作为较小容量高速SSD的OSD的默认allocator,是一个非常好的选择。

在Q版实现了HybridAllocator,这便是为了解决Avl allocator内存超标而设计的。

HybridAllocator继承AvlAllocator,并可能管理了一个BitmapAllocator。当AvlAllocator的内存占用量并不高没超过阈值时,HybridAllocator等同于AvlAllocator;当内存用量超过阈值时,HybridAllocator退化为BitmapAllocator,但仍然使用HybridAllocator来缓存那些比较大的free分区,以加速查找过程。

Q版的BtreeAllocator,这个是一位大神实现的,但不知为何没有被添加为默认的allocator,翻阅了社区的邮件,可能是因为没有足够标准的benchmark工具来证明BtreeAllocator的优越性,所以搁置了。

BtreeAllocator与Avl allocator极其相似,查找、分配、释放逻辑基本一致。差别在于,它使用两棵B树,而AvlAllocator使用AVL树。B树相对AVL树更节约内存,且具有相当的查找效率,但其左右旋等结构变更操作相对于AVL树更复杂。所以二者的取舍是比较难的,理论上那分高下,只能用标准benchmark工具来一决雌雄,但貌似社区还没有这个工具。
不知后续版本如何发展,静观其变吧。

最后再来分析一下BlueFS的空间管理策略。

wal + db + block

slow设备是BlueStore和BlueFS共用的,BlueStore的Allocator实例与BlueFS中Slow设备对应的Allocator是同一个实例。作为改进,二者的alloc_size也保持了一致,避免了以前版本alloc size不一致而引起的空间碎片化加剧问题。

WAL和DB设备由BlueFS独占使用,BlueStore不直接使用这片空间。在上图WAL、DB、Block设备齐全的情况下,BDEV_WAL和BDEV_DB各自拥有一个独立的Allocator实例。基于配置,这些Allocator可以是前文所述的各种类型。

db + block

没有独立的WAL设备时,BlueFS中也没有与之对应的bdev和allocator。

wal + block

需要注意的是,当没有独立的DB设备时,BlueFS中将Block设备直接当成共享的DB设备使用,BlueFS中就没有Slow设备了。

block only

当WAL和DB设备均没有的时候,BlueFS中仅有一个设备,它将Block设备直接当成共享的DB设备使用,没有BDEV_WAL和BDEV_SLOW。

一个需要注意的点是:bluefs的allocator构成一个数组,依次对应BDEV_WAL、BDEV_DB、BDEV_SLOW。在分配空间时,若BDEV_WAL allocator分配不出足够的空间,会降级用BDEV_DB allocator分配,若仍然不能够分配足够空间,则再次降级到BDEV_SLOW allocator,若还是不足,才会出现enospc错误。

另一个注意点是:每次_allocate调用,只从一个设备分配空间。例如需要BDEV_WAL allocator分配64K,而只分配出16K,那么,会将这16K还回去,然后尝试从BDEV_DB allocator分配全部64K,注意并不是分配剩下的48K。这样做可以简化日志结构。

不同的文件类型,其开始分配空间的设备是不同的,见下图。


有独立WAL设备配置

BlueStore在mkfs流程中,会在BlueFS中创建db.wal、db、db.slow几个目录,而后将这些目录通过rocksdb的options传递给rocksDB,rocksDB在写入log文件时,就会选择db.wal目录,写入SST文件时,就会按照配置的db_paths,顺序使用db和db.slow目录。这样,rocksdb上层与bluefs下层在数据分布上达成一致。

BlueFS自身logfile和rocksdb的log file,均有限写入WAL设备;db目录的文件优先写入block.db设备;db.slow目录的设备则写入block设备。

没有WAL设备

当WAL设备不存在时,rocksdb的log file会写到db目录下。无论block.db设备是否存在,BlueFS的db目录都是存在的,只不过该目录的数据可能写到block设备上去而已。

最后,注意options中的disableWAL是指rocksdb不写log file,BlueFS的log file是无论怎样都存在的,依然会优先向block.wal设备去写。注意区别rocksdb log file、BlueFS log file和block.wal设备几个概念的区别和联系,不可混为一谈。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容