一场由 mon_osd_full_ratio参数引发的辛酸史!!
【背 景】 :
在ceph 12.2.XXX集群中把mon_osd_full_ratio设置为99%以后,当磁盘空间使用率达到此报停水位后,集群并没有报停,而是由于磁盘空间消耗殆尽,BlueFS::_allocate分配不到磁盘空间导致整个池中的osd全部挂掉,此后osd再也无法拉起。
此时想到的是通过扩容bluefs来解决此问题。为此就开始梳理bluefs 扩容,FreelistManager,Allocator。。。。。
【日志报错】:
首次报错:bluefs _allocate failed to allocate 0x400000 on bdev 1,free 0x200000;fallback ro bdev 2
bluefs _allocate failed to allocate 0x400000 on bdev 2
FAILED assert(r=0)
第一次挂掉后,再次启动osd:触发断言:FAILED assert(0 == "bluefs enospc")
【bluefs 三类磁盘空间】
对于blusfs在逻辑上有3个层次的存储空间:
a)超高速空间-WAL:这类空间主要用于存储RocksdbDB内部产生的.log文件,可由NVME SSD或者NVRAM等延时相较普通SSD更小的设备充当。超高速空间也由BlueFs直接管理。
b)高速空间-DB:这类空间主要用于存储BlueStore内部产生的元数据(例如onode),可以由普通的SSD提供。Bluestore的元数据都交由RocksDB管理,而RocksDB最终通过BlueFs将数据存盘,所有这类空间也由BlueFs直接管理。
c)慢速空间-slow:这类空间主要用于存储对象数据,可由普通大容量机械盘提供,由Bluestore自行管理。
在生产环境中如果不区分以上3类存储空间,那么默认情况下BlueStore将自身管理的一部分空间拿出来与BlueFs进行共享(默认共享整个磁盘的4%空间),并在运行过程中进行实时监控和动态调整,具体策略是BlueStore通过BlueStore::_kv_sync_thread周期性的被唤醒,实时查询BlueFs的可使用空间,通过函数_balance_bluefs_freespace实现空间均衡,如果BlueFs可使用空间在整个BlueStore可用空间中的占比过小,则从bluestore空间中新分配一定量的空间赠送给BlueFs。反之如果BlueFs的可用空间在整个BlueStore可用空间占比过大,则从BlueFs中回收一部分空间到BlueStore。
如果划分了WAL和DB空间,对于.log文件以及BlueFs自身产生的日志文件总是优先使用WAL类型的设备空间。对于.sst文件,则优先使用DB类型的设备空间。若此时WAL空间不足,则选择DB空间; 若DB仍然不足,则选择使用SLOW类型的设备空间.
【BlueFs空间管理】
mkfs:
- 默认情况下不分区,设置DB空间与Bluestore空间共享。默认共享4%,并把空间起始位置和长度保持在bluefs_extents集合中。
2.在函数_open_fm中把bluefs_extents写入数据库。
mount:上电流程
- 依据bluefs 文件系统的日志恢复出bluefs空间的使用情况,分别填充到bluefs的分配器中。
alloc[id]->init_add_free(offset, length);
alloc[id]->init_rm_free(offset, length); - 依据日志回放(BlueFS::_replay)构建的文件列表(file_map),在bluefs的分配器中标记已经使用的磁盘空间。
- 从数据库中获取bluefs_extents。
- 从数据库中获取整个bluestore的空闲空间列表。并且把空闲空间填入bluestore的分配器中。
- 在bluestore的空闲空间列表中把bluefs的空间(bluefs_extents代表的空间即为bluefs空间)标记为已经使用。
上电后写流程空间分配:
- io到达bluestore层后通过alloc->allocate申请空间,并在BlueStore::_txc_finalize_kv函数中写入数据库,通过fm->allocate落盘。
- 元数据使用空间,最终会通过rocksdb中调用bluefs内部的allocate分配器分配空间并记录到对应文件的extent列表里面。
bluestore和bluefs空间数据均衡:
- BlueStore 与 BlueFs磁盘空间均衡函数入口:BlueStore::_kv_sync_thread---->_balance_bluefs_freespace
- 当bluefs空见不足后会提前从bluestore的分配器中申请一部分空间给bluestore使用。并写入bluefs_extents然后,写入数据库。
allocate和freelistmanager相关函数详细如下:
社区扩容代码参考:
https://github.com/ceph/ceph/commit/69a43efccfd3289a3ffec1d76dc4b4a208e0ec0c