您好,登錄后才能下訂單哦!
前面介紹了
BlueStore的BitMap分配器,我們知道新版本的
Bitmap
分配器的優勢在于
使用連續的內存空間從而盡可能更多的命中CPU Cache以提高分配器性能。在這里我們了解一下基于區間樹的
Stupid
分配器(類似于Linux Buddy內存管理算法),并對比分析一下其優劣。
Linux內存管理算法為了能夠快速響應請求,盡可能的提高內存利用率同時減少外部內存碎片,引入了伙伴系統算法
Buddy-System
。該算法將所有的空閑頁分組為11個鏈表,每個鏈表分別包含
1、2、4、8、16、32、64、128、256、512、1024
個連續的頁框塊,每個頁框塊的第一個內存頁的物理地址是該塊大小的整數倍。
伙伴的特點是:兩個塊大小相同、兩個塊地址連續、第一塊的第一個頁框的物理地址是兩個塊總大小的整數倍(同屬于一個大塊,第1塊和第2塊是伙伴,第3塊和第4塊是伙伴,但是第2塊和第3塊不是伙伴)。具體內存分配和內存釋放可自行Google。
優點:
缺點:
CMA
(Contiguous Memory Allocator, 連續內存分配器)。Stupid分配器使用了區間樹組織數據結構,高效管理
Extent(offset, length)
。
class StupidAllocator : public Allocator { CephContext* cct; // 分配空間用的互斥鎖 std::mutex lock; // 空閑空間總大小 int64_t num_free; // 最后一次分配空間的位置 uint64_t last_alloc; // 區間樹數組,初始化的時候,free數組的長度為10,即有十顆區間樹 std::vector<interval_set_t> free; // extent: offset, length typedef mempool::bluestore_alloc::pool_allocator< pair<const uint64_t, uint64_t>> allocator_t; // 有序的 btree map,按順存放extent。 typedef btree::btree_map<uint64_t, uint64_t, std::less<uint64_t>, allocator_t> interval_set_map_t; // 區間樹,主要的操作有 insert、erase等。 typedef interval_set<uint64_t, interval_set_map_t> interval_set_t; };
每顆區間樹的下標為
index(0-9)
,index(1-9)表示的空間大小為:
[2^(index-1) * bdev_block_size, 2^(index) * bdev_block_size)
,
初始化Stupid分配器后,調用者會向Allocator中加入或者刪除空閑空間。
// 增加空閑空間 void StupidAllocator::init_add_free(uint64_t offset, uint64_t length) { std::lock_guard<std::mutex> l(lock); // 向 free 中插入空閑空間 _insert_free(offset, length); // 更新空閑空間大小 num_free += length; } // 刪除空閑空間 void StupidAllocator::init_rm_free(uint64_t offset, uint64_t length) { std::lock_guard<std::mutex> l(lock); interval_set_t rm; rm.insert(offset, length); for (unsigned i = 0; i < free.size() && !rm.empty(); ++i) { interval_set_t overlap; overlap.intersection_of(rm, free[i]); // 刪除相應空間 if (!overlap.empty()) { free[i].subtract(overlap); rm.subtract(overlap); } } num_free -= length; // 更新可用空間 }
區間樹實現代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h
insert函數代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h#L445
erase函數代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h#L516
最核心的實現是向區間樹中插入以及刪除區間,代碼如下:
// 根據區間的長度,選取將要存放的區間樹,長度越大,bin值越大。 unsigned StupidAllocator::_choose_bin(uint64_t orig_len) { uint64_t len = orig_len / cct->_conf->bdev_block_size; // cbits = (sizeof(v) * 8) - __builtin_clzll(v) // __builtin_clzll 返回前置的0的個數 // cbits 結果是最高位1的下標(從0開始),len越大,值越大 int bin = std::min(int)cbits(len), (int)free.size() - 1); return bin; } void StupidAllocator::_insert_free(uint64_t off, uint64_t len) { // 計算該段空閑空間屬于哪個區間樹 unsigned bin = _choose_bin(len); while (true) { // 空閑空間插入區間樹 free[bin].insert(off, len, &off, &len); unsigned newbin = _choose_bin(len); if (newbin == bin) break; // 插入數據后,可能合并區間,導致區間長度增大,可能要調整bin,此時需要將舊的刪除,然后插入新的bin // 區間合并有兩種情況:一是合并在原有區間前面;而是合并在原有區間后面。 free[bin].erase(off, len); bin = newbin; } }
回顧第一節伙伴算法, 兩種合并的方式是有區別的:
區間樹刪除Extent比較簡單,在原來Extent刪除傳入的Extent,然后計算最終Extent是否落入其他區間樹,如果落入則從此區間樹刪除,加入新的區間樹。
空間分配的函數定義如下:
allocate(uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size, int64_t hint,PExtentVector* extents); allocate_int(uint64_t want_size, uint64_t alloc_unit, int64_t hint, uint64_t* offset, uint32_t* length)
其中
hint
是一個很重要的參數,表示分配的起始地址要盡量大于hint的值。
核心流程為4個2層for循環大致為:優先從hint地址依次向高級區間樹開始分配長度大于等于
want_size
的連續空間,如果沒有,則優先從hint地址依次向低級區間樹開始分配長度大于等于
alloc_unit
的連續空間(長度會大于alloc_unit)。
簡單的空間分配圖如下:
詳細的空間分配流程圖如下:
空間釋放的函數定義如下:
release(const interval_set<uint64_t> &release_set)
流程很簡單,先加鎖,然后循環調用
_insert_free
插入到對應區間樹里面,會涉及到相鄰空閑空間的合并,但是會導致分配空間碎片的問題。
Stupid底層使用BtreeMap來存儲一系列的Extent,內存不一定是連續的,同時在分配空間遍歷區間樹時,雖然區間樹里面的Extent是有序的,但是由于內存不一定是連續或者相鄰的兩個Extent內存跨度可能很大,都會導致CPU-Cache預讀不到下一個Extent,從而不能很好的利用CPU-Cache。
Bitmap分配器在BlueStore初始化時就初始化好了3層,而且大小是固定的,同時分配空間是依次順序分配,從而可以充分的利用CPU-Cache的功能。從而提高分配器的性能。
基于Extent的Stupid分配器存在偽空間碎片( 物理空間是連續的,但是分配器中卻不連續)問題:
一個24K的連續空間,經過6次4K分配和亂序的6次4K釋放后,可能會變成
8K + 4K + 8K + 4K
四塊空間。
其中兩個4K的區間由于和周邊塊大小一樣,所以落到不同的區間樹中,導致很難被合并,24K的連續空間變成了四塊不連續空間。
Bitmap分配器由于初始化時就分配好了3層所有內存,而且3層都是有序的的同時分配空間是順序遍歷的,在釋放空間的時候設置相應位就可以,不影響連續性,所以不存在這個問題。
據Bitmap作者的 性能對比實驗來看,Bitmap分配器要好于Stupid,等Bitmap穩定后,可以設置BlueStore的默認分配器為Bitmap。
作者:史明亞
現在注冊滴滴云,有機會可得30元無門檻滴滴出行券
新購云服務1月5折 3月4.5折 6月低至4折
滴滴云使者招募,推薦最高返傭50%
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。