前面介紹了
BlueStore的BitMap分配器,我們知道新版本的
Bitmap
分配器的優(yōu)勢在于
使用連續(xù)的內(nèi)存空間從而盡可能更多的命中CPU Cache以提高分配器性能。在這里我們了解一下基于區(qū)間樹的
Stupid
分配器(類似于Linux Buddy內(nèi)存管理算法),并對比分析一下其優(yōu)劣。
創(chuàng)新互聯(lián)主要從事做網(wǎng)站、網(wǎng)站設計、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務岱山,10余年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18982081108
Linux內(nèi)存管理算法為了能夠快速響應請求,盡可能的提高內(nèi)存利用率同時減少外部內(nèi)存碎片,引入了伙伴系統(tǒng)算法
Buddy-System
。該算法將所有的空閑頁分組為11個鏈表,每個鏈表分別包含
1、2、4、8、16、32、64、128、256、512、1024
個連續(xù)的頁框塊,每個頁框塊的第一個內(nèi)存頁的物理地址是該塊大小的整數(shù)倍。
伙伴的特點是:兩個塊大小相同、兩個塊地址連續(xù)、第一塊的第一個頁框的物理地址是兩個塊總大小的整數(shù)倍(同屬于一個大塊,第1塊和第2塊是伙伴,第3塊和第4塊是伙伴,但是第2塊和第3塊不是伙伴)。具體內(nèi)存分配和內(nèi)存釋放可自行Google。
優(yōu)點:
缺點:
CMA
(Contiguous Memory Allocator, 連續(xù)內(nèi)存分配器)。Stupid分配器使用了區(qū)間樹組織數(shù)據(jù)結(jié)構(gòu),高效管理
Extent(offset, length)
。
class StupidAllocator : public Allocator { CephContext* cct; // 分配空間用的互斥鎖 std::mutex lock; // 空閑空間總大小 int64_t num_free; // 最后一次分配空間的位置 uint64_t last_alloc; // 區(qū)間樹數(shù)組,初始化的時候,free數(shù)組的長度為10,即有十顆區(qū)間樹 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; // 區(qū)間樹,主要的操作有 insert、erase等。 typedef interval_set<uint64_t, interval_set_map_t> interval_set_t; };
每顆區(qū)間樹的下標為
index(0-9)
,index(1-9)表示的空間大小為:
[2^(index-1) * bdev_block_size, 2^(index) * bdev_block_size)
,
初始化Stupid分配器后,調(diào)用者會向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; // 更新可用空間 }
區(qū)間樹實現(xiàn)代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h
insert函數(shù)代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h#L445
erase函數(shù)代碼:
https://github.com/ceph/ceph/blob/master/src/include/interval_set.h#L516
最核心的實現(xiàn)是向區(qū)間樹中插入以及刪除區(qū)間,代碼如下:
// 根據(jù)區(qū)間的長度,選取將要存放的區(qū)間樹,長度越大,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的個數(shù) // cbits 結(jié)果是最高位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) { // 計算該段空閑空間屬于哪個區(qū)間樹 unsigned bin = _choose_bin(len); while (true) { // 空閑空間插入?yún)^(qū)間樹 free[bin].insert(off, len, &off, &len); unsigned newbin = _choose_bin(len); if (newbin == bin) break; // 插入數(shù)據(jù)后,可能合并區(qū)間,導致區(qū)間長度增大,可能要調(diào)整bin,此時需要將舊的刪除,然后插入新的bin // 區(qū)間合并有兩種情況:一是合并在原有區(qū)間前面;而是合并在原有區(qū)間后面。 free[bin].erase(off, len); bin = newbin; } }
回顧第一節(jié)伙伴算法, 兩種合并的方式是有區(qū)別的:
區(qū)間樹刪除Extent比較簡單,在原來Extent刪除傳入的Extent,然后計算最終Extent是否落入其他區(qū)間樹,如果落入則從此區(qū)間樹刪除,加入新的區(qū)間樹。
空間分配的函數(shù)定義如下:
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
是一個很重要的參數(shù),表示分配的起始地址要盡量大于hint的值。
核心流程為4個2層for循環(huán)大致為:優(yōu)先從hint地址依次向高級區(qū)間樹開始分配長度大于等于
want_size
的連續(xù)空間,如果沒有,則優(yōu)先從hint地址依次向低級區(qū)間樹開始分配長度大于等于
alloc_unit
的連續(xù)空間(長度會大于alloc_unit)。
簡單的空間分配圖如下:
詳細的空間分配流程圖如下:
空間釋放的函數(shù)定義如下:
release(const interval_set<uint64_t> &release_set)
流程很簡單,先加鎖,然后循環(huán)調(diào)用
_insert_free
插入到對應區(qū)間樹里面,會涉及到相鄰空閑空間的合并,但是會導致分配空間碎片的問題。
Stupid底層使用BtreeMap來存儲一系列的Extent,內(nèi)存不一定是連續(xù)的,同時在分配空間遍歷區(qū)間樹時,雖然區(qū)間樹里面的Extent是有序的,但是由于內(nèi)存不一定是連續(xù)或者相鄰的兩個Extent內(nèi)存跨度可能很大,都會導致CPU-Cache預讀不到下一個Extent,從而不能很好的利用CPU-Cache。
Bitmap分配器在BlueStore初始化時就初始化好了3層,而且大小是固定的,同時分配空間是依次順序分配,從而可以充分的利用CPU-Cache的功能。從而提高分配器的性能。
基于Extent的Stupid分配器存在偽空間碎片( 物理空間是連續(xù)的,但是分配器中卻不連續(xù))問題:
一個24K的連續(xù)空間,經(jīng)過6次4K分配和亂序的6次4K釋放后,可能會變成
8K + 4K + 8K + 4K
四塊空間。
其中兩個4K的區(qū)間由于和周邊塊大小一樣,所以落到不同的區(qū)間樹中,導致很難被合并,24K的連續(xù)空間變成了四塊不連續(xù)空間。
Bitmap分配器由于初始化時就分配好了3層所有內(nèi)存,而且3層都是有序的的同時分配空間是順序遍歷的,在釋放空間的時候設置相應位就可以,不影響連續(xù)性,所以不存在這個問題。
據(jù)Bitmap作者的 性能對比實驗來看,Bitmap分配器要好于Stupid,等Bitmap穩(wěn)定后,可以設置BlueStore的默認分配器為Bitmap。
作者:史明亞
現(xiàn)在注冊滴滴云,有機會可得30元無門檻滴滴出行券
新購云服務1月5折 3月4.5折 6月低至4折
滴滴云使者招募,推薦最高返傭50%
分享題目:BlueStore源碼分析之Stupid分配器
文章網(wǎng)址:http://aaarwkj.com/article24/igcice.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、網(wǎng)站設計公司、網(wǎng)站導航、企業(yè)網(wǎng)站制作、網(wǎng)站設計、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)