ceph bluestore 源码分析:ceph-osd内存查看方式及控制源码分析
文章目錄
- 內存查看
- 內存控制
- 內存控制源碼分析
- 通過gperftools接口獲取osd進程實際內存 動態設置cache大小
- 動態調整cache比例
- trim釋放內存
本文通過對ceph-osd內存查看跟蹤的5種手段以及osd內存控制的方式進行源碼層面的說明,并未通過修改相關源碼進行控制(水平不夠),僅限于使用社區已開發好的參數進行相關配置的跟進而已,如想要追求更加精確的理解,可以對
osd/bluestore/rocksdb相關源碼實現進行閱讀
ceph版本
12.2.1 -
12.2.12
內存查看
-
最常用的內存初始查看方法
top -u ceph |grep ceph-osd,通過交互式輸入c,2次e即可看到如下效果。其中單個osd進程占用內存為res欄
-
ceph tell osd.0 heap stats
這種方式主要查看osd運行過程中占用的內存:
第一項:Bytes in use by application包括bluestore cache,rocksdb_cache,bluefs,pglog等數據信息
第二項:Bytes in page heap freelist內存頁堆管理的空閑空間鏈表
第三項:Bytes in central cache freelist中心緩沖區占用
第四項:Bytes in transfer cache freelist交換緩沖區占用
第五項:Bytes in thread cache freelists線程緩沖區占用
第六項:Bytes in malloc metadatamalloc為元數據分配的空間ceph是使用tcmalloc 空間分配器進行空間分配,其中由tcmalloc分配的但是并未被ceph進程使用的空間可以通過
ceph tell osd.id heap release
-
google-perftools工具實時跟蹤osd/mon進程內存占用,精確到具體的函數。關于pprof的安裝以及如何使用其來查看osd內存占用,可以參考pprof搭配ceph tell命令分析ceph內存
效果如下:(pprof) top10 Total: 2525 samples 298 11.8% 11.8% 345 13.7% runtime.mapaccess1_fast64 268 10.6% 22.4% 2124 84.1% main.FindLoops 251 9.9% 32.4% 451 17.9% scanblock 178 7.0% 39.4% 351 13.9% hash_insert 131 5.2% 44.6% 158 6.3% sweepspan 119 4.7% 49.3% 350 13.9% main.DFS96 3.8% 53.1% 98 3.9% flushptrbuf95 3.8% 56.9% 95 3.8% runtime.aeshash6495 3.8% 60.6% 101 4.0% runtime.settype_flush88 3.5% 64.1% 988 39.1% runtime.mallocgc...各個參數含義如下:
-
The first column contains the direct memory use in MB. 函數本身使用的內存
-
The fourth column contains memory use by the procedure and all of its callees.函數本身內存+調用函數內存
-
The second and fifth columns are just percentage representations of the numbers in the first and fourth columns. 第二第五列分別為第一列,第四列與total的比值
-
The third column is a cumulative sum of the second column.第三列為(到當前行數為止)第二列所有的和
注意:該命令需要
heap start_profiler長期運行才能夠利用pprof抓取更多有效信息。 -
-
ceph原生命令,由ceph內存池(bstore線程)管理的內存各項數據占用,可以通過調整
mempool_debug = true參數來查看詳細打印
ceph daemon osd.16 dump_mempools
打印信息如下:
這里能夠看到內存池中各個數據結構的items個數和bytes總空間大小,關于當前命令如何動態獲取各個數據結構的內容相關得源碼分析可以參考admin_socket實時獲取內存池數據 文章
-
valgrind搭配massif,查看進程內存占用,能夠看到內存分配棧并且精確到具體的函數;詳細的配置以及更加高級全面的內存查看方法可以參考valgrind搭配massif、vgdb分析ceph-mon內存
linux端的mon進程占用效果查看如下:
最下側即為進程內存占用棧,并且在運行時間點上提供快照以及峰值的內存占用情況,能夠很清晰得看到各個時間點內存如何上漲上來,同時massif提供可視化的圖形頁面(火焰圖)來查看進程內存:
內存控制
本文的內存控制版本基于ceph 12.2.12版本,相關的參數描述同樣是基于12.2.12版本,當前12.2.12ceph版本真正實現了osd進程內存的精準控制
bluestore相關參數說明
bluestore_min_alloc_size_hdd = 65536 #hdd做osd時的bluestore 分配空間的最小粒度 64K
bluestore_min_alloc_size_ssd = 16384 #ssd做osd時bluestore分配空間的最小粒度 16K
bluestore_cache_size_hdd = 1073741824 #hdd做osd時的bluestore_cache的大小,1G,該參數主要用于緩存元數據,鍵值數據以及部分data數據
bluestore_cache_size_ssd = 3221225472 #ssd做osd時的bluestore_cache的大小,默認3G
bluestore_cache_trim_interval = 0.05 #bluestore cache 裁剪的時間間隔,每隔0.05秒會嘗試對不使用的cache種的數據(onode,blob,extents)釋放
bluestore_cache_trim_max_skip_pinned = 64 #每次trim時的onode的個數
osd內存相關控制參數
osd_memory_base = 805306368 #osd內存占用的最小值,默認768M
osd_memory_target = 838860800 # 真正限制osd內存的上限,即我們top 種看到的進程實際內存占用會維持在當前參數設置的值以下。這里我們設置的800M
osd_memory_cache_min = 134217728 #osd 內存 cache占用的最小值,128M
osd_memory_cache_resize_interval = 1.0 #osd cache大小的實際調整的時間間隔,每隔1秒,進行一次cache大小的調整
bluestore_cache_autotune_interval = 5 #osd每隔5秒調整一次bluestore cache的比例
bluestore_cache_autotune_chunk_size = 33554432 #osd每次調整 bluestore cache的最小單位,32M
bluestore_cache_kv_ratio = 0.4 #bluestore cache 存儲鍵值cache的比例
bluestore_cache_meta_ratio = 0.4 #bluestore cache 存儲元數據cache的比例
內存控制源碼分析
主要內存控制方式是通過在osd_memory_cache_resize_interval時間間隔內獲取osd進程的實際內存,判斷其是否超過設定的osd_memory_target的數值,并進行cache大小的調整,最終通過trim釋放內存。
關鍵地實現難點為以下幾個地方:
- 獲取osd進程的實際內存
- 動態調整cache比例
- 動態設置cache大小
- trim釋放內存
通過gperftools接口獲取osd進程實際內存 動態設置cache大小
因為ceph內存分配使用的tcmalloc進行的,ceph這里是通過gperftools提供的獲取tcmalloc內存分配的接口進行獲取
src/os/bluestore/BlueStore.cc 在bstore的線程函數種void *BlueStore::MempoolThread::entry()
通過_tune_cache_size調用gperttools提供的tcmalloc獲取內存分配的接口獲取內存大小
將最終需要調整的cache大小已全局變量auto_tune_size返回
關于gperftools獲取已占有內存的接口實現可以github下載gperftools-master源碼https://github.com/gperftools/gperftools,這里僅貼出將未使用內存頁但以申請的內存頁釋放回操作系統的代碼調用,其他獲取總的內存頁接口和未使用內存頁接口詳細實現有興趣的同學可以去看看:
void ceph_heap_release_free_memory()
{MallocExtension::instance()->ReleaseFreeMemory();
}void MallocExtension::ReleaseFreeMemory() {ReleaseToSystem(static_cast<size_t>(-1)); // SIZE_T_MAX
}virtual void ReleaseToSystem(size_t num_bytes) {SpinLockHolder h(Static::pageheap_lock());if (num_bytes <= extra_bytes_released_) {// We released too much on a prior call, so don't release any// more this time.extra_bytes_released_ = extra_bytes_released_ - num_bytes;return;}num_bytes = num_bytes - extra_bytes_released_;// num_bytes might be less than one page. If we pass zero to// ReleaseAtLeastNPages, it won't do anything, so we release a whole// page now and let extra_bytes_released_ smooth it out over time.Length num_pages = max<Length>(num_bytes >> kPageShift, 1);size_t bytes_released = Static::pageheap()->ReleaseAtLeastNPages(num_pages) << kPageShift;if (bytes_released > num_bytes) {extra_bytes_released_ = bytes_released - num_bytes;} else {// The PageHeap wasn't able to release num_bytes. Don't try to// compensate with a big release next time. Specifically,// ReleaseFreeMemory() calls ReleaseToSystem(LONG_MAX).extra_bytes_released_ = 0;}}
動態調整cache比例
關于bluestore cache的作用,很明顯,將高命中的臟數據(kv數據,元數據)等數據放入到緩存種,加速bluestore io讀寫能力。
其中bluestore cache維護了一個cache優先級列表如下
最高優先級為kv cache,其次 meta cache,最后剩余的提供給data cache。
優先級越高的cache,分配內存資源,調整內存資源優先分配。當然占用的大小則是由我們以上圖的兩個ratio參數進行控制。
- 初始化cache,設置優先級cache內存占用的比例
_adjust_cache_settings(); void BlueStore::MempoolThread::_adjust_cache_settings() {store->db->set_cache_ratio(store->cache_kv_ratio);meta_cache.set_cache_ratio(store->cache_meta_ratio);data_cache.set_cache_ratio(store->cache_data_ratio); } - 動態調整 cache
從動態設置cache大小中tune_cache_size獲取到的可以分配的cache大小auto_tune_cache_size,將其根據各個cache的ratio比例分配給優先級cache
針對每個優先級Cache的大小調整則遵循如下規則:void BlueStore::MempoolThread::_balance_cache( const std::list<PriorityCache::PriCache *>& caches) {//初始值為osd內存最小值 osd_memory_cache_min 128M,該值在tune_cache_size種動態調整int64_t mem_avail = autotune_cache_size;//根據對應cache的優先級進行cache容量的分配// Assign memory for each priority levelfor (int i = 0; i < PriorityCache::Priority::LAST + 1; i++) {ldout(store->cct, 10) << __func__ << " assigning cache bytes for PRI: " << i << dendl;PriorityCache::Priority pri = static_cast<PriorityCache::Priority>(i);_balance_cache_pri(&mem_avail, caches, pri);}//將剩余的未分配的cache 按照比例再重新分配// Assign any leftover memory based on the default ratios.if (mem_avail > 0) {for (auto it = caches.begin(); it != caches.end(); it++) {int64_t fair_share =static_cast<int64_t>((*it)->get_cache_ratio() * mem_avail);if (fair_share > 0) {(*it)->add_cache_bytes(PriorityCache::Priority::LAST, fair_share);}}}// assert if we assigned more memory than is available.assert(mem_avail >= 0);// Finally commit the new cache sizesfor (auto it = caches.begin(); it != caches.end(); it++) {(*it)->commit_cache_size();} }- 獲取優先級cache想要的容量,通過
bluestore_cache_autotune_chunk_size34M單位進行分配 - 優先級cache 想要的容量大于cache剩余容量,將cache剩余的容量都提供給當前優先級cache
- 優先級cache 想要的容量小于cache剩余容量,直到分配足夠
- 獲取優先級cache想要的容量,通過
trim釋放內存
每隔bluestore_cache_trim_interval會嘗試釋放一次內存,每次嘗試釋放元數據的個數為bluestore_cache_trim_max_skip_pinned,釋放內存后當osd總內存超過osd_memory_target,則不再進行cache相關的大小調整;否則仍然繼續將未超過的部分應用于cache分配。
計算好需要trim的元數據個數和緩存大小,調用對應的cache trim函數。
bluestore默認使用的是淘汰算法更優的TwoQCache,則調用對應的void BlueStore::TwoQCache::_trim(uint64_t onode_max, uint64_t buffer_max)執行內存釋放即可。
關于內存控制,osd_memoiry_target及其一系列控制衍生參數尤為關鍵。ceph在L版本低版本并未做得足夠完善,但是L版本的最新版已經將內存控制邏輯完善,總之在保證性能的前提下OSD內存控制更加更加精準。
總結
以上是生活随笔為你收集整理的ceph bluestore 源码分析:ceph-osd内存查看方式及控制源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 飞度最低配多少钱?
- 下一篇: 说给你听是哪首歌啊?