ceph bluefs


 一場由 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相關函數詳細如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM