牛虻与专家

导航

 

 一场由 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空间管理ceph 12.2.12】

StupidAllocator主要接口:

接口名称 含义
init_add_free() BluieStore上电时,通过BitmapFreelistManager读取磁盘中的空闲空间,然后使用此接口把空闲标记为空闲
init_rm_free() 将指定范围的空间标记为已经分配
allocate() 分配空间,分配的空间不一定是连续的,可能是一些离散的断。

        关键点:Allocator的使用者包含BlueFS和BlueStore,BlueFS通过文件系统的日志文件固化磁盘空间使用情况,BlueStore通过FreelistManager将磁盘空间信息固化到rocksdb中

BitmapFreelistManager:

接口名称 含义
allocate() 从BitmapFreelistManager中分配指定范围的空间
enumerate_reset() 上电时,bluestore通过这个2个接口遍历BitmapFreelistManager中所有空闲段,并将BlueStore的分配器进行初始化,从而还原上次下电时Allocator对应的内存结构
enumerate_next()

 

以下依据Bluestore创建,上电以及io写入时BitmapFreelistManager和StupidAllocator的使用进行分析:

mkfs:   

  1. 默认情况下不分区,设置DB空间与Bluestore空间共享。默认共享4%,并把空间起始位置和长度保持在bluefs_extents集合中。

     2.在函数_open_fm中把bluefs_extents写入数据库。

 

 

 

 mount:上电流程

  1.   依据bluefs 文件系统的操作日志(OP_ALLOC_ADD,OP_ALLOC_RM)恢复出bluefs空间的使用情况,分别调用以下分配器接口填充到bluefs的分配器中。

         alloc[id]->init_add_free(offset, length);
         alloc[id]->init_rm_free(offset, length);

  2. 依据日志回放(BlueFS::_replay)构建出文件列表(file_map),然后bluefs分配器依据file_map把占用的磁盘空间空间标记为已经使用。
  3. 从数据库中获取bluefs_extents。

  4. FreelistManager从数据库中获取整个bluestore的空闲空间列表。并且把空闲空间填入bluestore的分配器中。

     

     

  5.  在bluestore的分配器中把bluefs的空间(bluefs_extents代表的空间即为bluefs空间)标记为已经使用。

上电后写流程空间分配:

  1. io到达bluestore层后通过alloc->allocate申请空间,并在BlueStore::_txc_finalize_kv函数中写入数据库,通过fm->allocate落盘。
  2. 元数据使用空间,最终会通过rocksdb中调用bluefs内部的allocate分配器分配空间并记录到对应文件的extent列表里面。

bluestore和bluefs空间数据均衡:

  1. BlueStore 与  BlueFs磁盘空间均衡函数入口:BlueStore::_kv_sync_thread---->_balance_bluefs_freespace
  2. 当bluefs磁盘空间不足后会提前从bluestore的分配器中申请一部分空间给bluefs使用。并写入bluefs_extents然后,写入数据库。

 

【解决方案】

    梳理以上流程后开始参考社区的进行扩容(问题已经解决):

    https://github.com/ceph/ceph/commit/69a43efccfd3289a3ffec1d76dc4b4a208e0ec0c

 

纸上得来终觉浅,绝知此事要躬行。根据本次的教训,一定要添加上磁盘告警水位限制:

       ceph osd set-full-ratio <float[0.0-1.0]>

       ceph osd set-nearfull-ratio <float[0.0-1.0]>

       cephosd set-backfillfull-ratio <float[0.0-1.0]>

 

 

allocate和freelistmanager相关函数详细如下:

 

posted on 2020-09-08 19:28  牛虻&专家  阅读(1745)  评论(0编辑  收藏  举报