成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

RocksDB 內存超限問題剖析

存儲
在使用 RocksDB 存儲引擎的過程中,有部分開發(fā)者遇到了內存使用超出預期的情況。本文針對這一問題展開了深入分析,從內存使用原理、RocksDB 內存管理機制、常見內存使用問題等方面進行了詳細探討,并提出了相應的解決方案和優(yōu)化建議......

一、背景

1.1 前言

在現(xiàn)代數(shù)據(jù)庫系統(tǒng)中,RocksDB 作為一種高性能的鍵值存儲引擎,廣泛應用于需要高吞吐量和低延遲的場景。然而,在使用過程中觀察到 RocksDB 的內存使用常常超出預設的閾值,這一現(xiàn)象對系統(tǒng)的穩(wěn)定性和可用性構成了嚴重威脅。

RocksDB 提供了通過 block-cache-size 參數(shù)來控制緩存使用的機制。開發(fā)者可以通過以下代碼片段設置緩存大小:

std::shared_ptr<rocksdb::Cache> cache = rocksdb::NewLRUCache(cache_size, -1, true);

然而,實際應用中發(fā)現(xiàn),RocksDB 的內存占用往往超出了設定的 cache_size 值。這種內存使用的不可預測性導致了內存分配的失控,甚至觸發(fā)了程序的 OOM(Out of Memory)錯誤,嚴重影響了服務的連續(xù)性和可靠性。

有部分開發(fā)者報告了相似的內存超額使用問題,該問題在 GitHub 社區(qū)也引起了廣泛關注。

1.2 內存分析流程

在分析內存的過程中,可以搭配許多 Linux 的命令工具來進行。以下是一套內存分析的基本思路:

圖片

圖片來源:https://learn.lianglianglee.com/

1、可以先用 free 和 top,查看系統(tǒng)整體的內存使用情況。
2、再用 vmstat 和 pidstat,查看一段時間的趨勢,從而判斷出內存問題的類型。
3、最后進行詳細分析,比如內存分配分析、緩存/緩沖區(qū)分析、具體進程的內存使用分析等。

其中,第一步和第二步可以觀察到內存問題的現(xiàn)象,而最難的往往是第三步,對內存的使用情況進行分析。第三步中需要結合業(yè)務代碼,對問題的根因提出假設,然后配合一些工具來驗證假設。分析的過程更像在做實驗:提出假設,收集數(shù)據(jù),驗證假設,得出結論。下文中,也會搭配內存工具進行分析,供讀者參考。

二、問題描述

在前文所述的 RocksDB 內存使用問題背景下,我們業(yè)務生產環(huán)境遭遇了相似的挑戰(zhàn)。應用程序采用 glibc 的 ptmalloc 作為內存分配器。在程序中,存在兩個 RocksDB 實例,分別用于存儲不同類型的數(shù)據(jù)。根據(jù)配置,兩個實例的 block-cache-size 分別被設定為4GB和8GB。然而,實際的內存消耗量遠遠超出了這一預設值,導致整體內存使用量顯著高于預期。

通過執(zhí)行 free -g 命令,監(jiān)測到程序的內存使用量達到了59GB,這一數(shù)值已經接近了物理服務器的內存容量閾值。此外,通過定期執(zhí)行 vmstat 3 命令,觀察到自服務啟動以來,內存使用量持續(xù)上升,直至接近100%的使用率。這一現(xiàn)象表明,系統(tǒng)內存已極度緊張,存在觸發(fā) OOM(Out of Memory)錯誤的風險。

鑒于當前內存使用情況,確認了內存管理問題的存在,并認識到需要進一步結合源代碼進行深入分析,以識別內存使用異常的根本原因,并探索相應的優(yōu)化措施。

名稱

信息

機器配置

32C64G 物理機

內存使用量

59G

RocksDB 實例數(shù)量

2

每個 RocksDB 實例文件夾大小

實例1:190G、實例2:180G

內存分配器

glibc ptmalloc

block_cache設置

實例1:4G、實例2:8G

三、分析過程

3.1 內存泄露分析

以下分析均在內部測試環(huán)境中進行,使用的是16C32G的機器。起初,懷疑 RocksDB 存在內存泄露,會不斷申請內存并且不會回收。

分析內存泄露的常用工具有 valgrind、memleak、strace、jemalloc 的 jeprof。這里用到的工具是 jemalloc 的 jeprof。jeprof 的原理主要是在內存的 malloc 和 free 的地方進行監(jiān)控并收集數(shù)據(jù),使用時可以設置定期打印數(shù)據(jù)。

通過 RocksDB 提供的的 db.getProperty()  方法對各個模塊占用內存情況進行取值,結果如下:

rocksdb.estimate-table-readers-mem: 16014055104  // 重點關注
rocksdb.block-cache-usage: 1073659024  // 重點關注

發(fā)現(xiàn)主要占用內存的地方有兩個:block-cache-usage 和  estimate-table-readers-mem。這兩個屬性分別對應了 RocksDB 中的 block_cache 以及 indexs/filters。

但是隨著時間的推移,block_cache 和 indexs/filters 會達到一個均衡點,不再增加上漲。與 RocksDB 存在內存泄露的假設不相符。

進一步分析 RocksDB 分配內存的調用堆棧,由于 glibc ptmalloc 無法打印調用堆棧,將 glibc ptmalloc 切換成了 jemalloc,通過 jeprof 進行內存調用堆棧的打印,以下是 jemalloc 的安裝方法:

# 用jemalloc 對于服務來說沒有改造成本。
# 可以直接使用LD_PRELOAD=/usr/local/lib/libjemalloc.so這種動態(tài)鏈接的方式去植入
# 前提是Linux機器上需要先安裝jemalloc:
wget https://github.com/jemalloc/jemalloc/archive/5.1.0.tar.gz tar zxvf jemalloc-5.1.0.tar.gz
cd jemalloc-5.1.0/
./autogen.sh
./configure --prefix=/usr/local/jemalloc-5.1.0 --enable-prof
make && make install_bin install_include install_lib

上述命令中,--enable-prof 代表開啟 jemalloc 的 jeprof 功能。

安裝完成后,通過 LD_PRELOAD 命令來開啟 jemalloc 的 malloc 和 free。LD_PRELOAD 的原理是直接使用 jemalloc 的 malloc 和 free 方法替換掉 glibc 的 malloc/free。

通過以下命令啟動程序:

export MALLOC_CONF="prof:true,lg_prof_interval:29"
LD_PRELOAD=/usr/local/jemalloc-5.1.0/lib/libjemalloc.so ./process_start

上述命令中 export MALLOC_CONF="prof:true,lg_prof_interval:29" 代表開啟 jeprof 的信息捕獲,內存每次上漲 2的29次方 btyes (512MB) 便記錄一次信息。最終輸出了結果,可以通過以下命令將結果轉成調用堆棧圖:

jeprof  --show_bytes --pdf ./process_start jeprof.34447.0.f.heap > result.pdf

最終觀察堆棧圖(只截取了部分)發(fā)現(xiàn),RocksDB 正常調用分配內存的方法:rocksdb::AllocateBlock,沒有觀察到有內存泄露的情況。

圖片

3.2 系統(tǒng) glibc ptmalloc 分析

搜索了很多類似的問題,發(fā)現(xiàn)也有開發(fā)者都遇到了 glibc 內存分配不釋放的問題,便懷疑是否是 glibc 的內存分配不合理導致的。目前線上環(huán)境 glibc 的版本是2.17。

圖片

查看了線上機器的 /proc/meminfo,大部分內存主要用在了程序申請的棧內存和堆內存中,可以看到下圖中 Active(anon)  匿名內存占用了52G,這部分內存申請后沒有被釋放。

glibc 申請的內存均屬于這部分內存。

圖片

其次,通過 pmap -X pid 查看進程的內存塊,發(fā)現(xiàn)有很多64MB的內存段。

圖片

為什么會創(chuàng)建這么多的64M的內存區(qū)域?這個跟 glibc 的內存分配器有關系。glibc 每次進行 mmap 分配時申請內存的大小在64位系統(tǒng)上默認為64MB。

此時便進一步提出了新的假設:是否因為 glibc 的內存分配機制不合理,導致內存不斷申請,但是不釋放資源?

分析 glibc 分配的內存情況,可以使用 glibc 提供的接口:

malloc_info(https://man7.org/linux/man-pages/man3/malloc_info.3.html

The malloc_info() function exports an XML string that describes the current state of the memory-allocation implementation in the caller. The string is printed on the file stream stream. The exported string includes information about all arenas.

以下為 malloc_info 的接口定義。該接口會將內存分配的情況直接以 XML 的形式輸出到文件中。

#include <malloc.h>
int malloc_info(int options, FILE *stream);

在程序中添加內存信息打印的代碼,每隔一段時間觸發(fā)一次打印:

FILE *filePointer;
filePointer = fopen("mem_info.log", "a");
if (filePointer != nullptr) {
  malloc_info(0, filePointer);
  fclose(filePointer);
}

以下為 malloc_info 輸出的內容(截取部分內容):

<malloc versinotallow="1">
<heap nr="0">
<sizes>
  <size from="17" to="32" total="32" count="1"/>
  <size from="33" to="48" total="48" count="1"/>
  <size from="81" to="96" total="1824" count="19"/>
  <size from="97" to="112" total="112" count="1"/>
  <size from="33" to="33" total="42636" count="1292"/>
  // ....
</sizes>
<total type="fast" count="22" size="2016"/>
<total type="rest" count="5509" size="33761685"/>
<system type="current" size="230117376"/>
<system type="max" size="230117376"/>
<aspace type="total" size="230117376"/>
<aspace type="mprotect" size="230117376"/>
</heap>

XML 內容闡述:

1.nr 即 arena,通常一個線程一個,線程間會相互爭搶 arena。

2.<size from="17" to="32" total="32" count="1"/>

大小在一定范圍內的內存,會放到一個鏈表里,這就是其中一個鏈表。from 是內存下限,to是上限,上面的意思是內存分配在 [17,32] 范圍內的空閑內存總共有32個。

3.<total type="fast" count="22" size="2016"/>

即 fastbin 這鏈表當前有22個空閑內存塊,大小為2016字節(jié)。

4.<total type="rest" count="5500" size="33761685"/>

除 fastbin 以外,所有鏈表空閑的內存數(shù)量,以及內存大小,此處內存塊數(shù)量為5509,大小為33761685字節(jié)。

因此,fast 和 rest 加起來為當前 glibc 中空閑的未歸還給操作系統(tǒng)的內存。通過命令 awk 將文件中所有 fast 和 rest 占用的內存加起來后,發(fā)現(xiàn)約為 4G 。

圖片

當前 RocksDB 進程的內存使用量為20.48G,上述提到 block-cache-usage 和 estimate-table-readers-mem 加起來只有15.9G (1073659024 bytes + 16014055104 bytes)。相當于中間差距還有4G左右。剛好和 glibc 占用的空閑內存相吻合。

圖片

最終確認是由于 glibc 的 ptmalloc 內存管理器申請內存不回收,導致了機器內存緊張。

四、問題解決

發(fā)現(xiàn)是 glibc ptmalloc 的問題之后,解決也相對簡單,業(yè)內有更好的 ptmalloc 替代方案,如 jemalloc 以及 tcmalloc。

將 jemalloc 應用到線上環(huán)境之后發(fā)現(xiàn),確實像預期那樣,內存的使用相比于 ptmalloc 更少,此前,機器的內存一直維持在高位,使用 jemalloc 之后,內存的使用下降了1/4(從95%+下降到80%+),隨著內存地釋放,有更多的內存可用于處理請求,IO和CPU的使用率就降低了,下圖是內存、磁盤IO使用率以及 CPU 空閑率的對比圖。

圖片

在相關性能指標得到優(yōu)化之后,服務可用性以及RT也得到了提升。

圖片

五、總結

在進行內存超量使用問題的分析過程中,最初懷疑是 RocksDB 存在一些內存管理不合理的地方導致了內存超量使用。然而,經過深入研究和分析,發(fā)現(xiàn)實際的原因主要由 glibc的 ptmalloc 內存回收機制所導致。整個分析過程較為繁瑣,需要結合一些合適的內存分析工具,逐層深入,不斷假設并驗證猜想。

總的來說,內存超量使用問題得到了解釋,也成功解決。通過逐步深入,持續(xù)假設和驗證,最終找到了真正的問題所在,希望能為讀者在解決類似問題上提供一些靈感和思路。

六、參考文獻

  1. https://github.com/facebook/rocksdb/wiki/Partitioned-Index-Filters
  2. https://github.com/facebook/rocksdb/wiki/Memory-usage-in-RocksDB
  3. http://jemalloc.net/jemalloc.3.htmlhttps://paper.seebug.org/papers/Archive/refs/heap/glibc%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86ptmalloc%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90.pdf
  4. https://man7.org/linux/man-pages/man3/malloc_info.3.html
責任編輯:龐桂玉 來源: vivo互聯(lián)網技術
相關推薦

2009-09-03 16:58:49

C#內存管理

2010-02-01 13:34:59

Python 腳本

2010-05-27 12:58:07

SVN升級

2011-07-18 17:14:16

Objective-C 內存 Cocoa

2010-02-23 10:32:20

Python 腳本

2009-10-19 10:52:48

綜合布線市場

2013-09-05 09:42:06

2010-02-05 18:00:18

Android源代碼

2010-02-06 15:32:30

Android架構

2010-02-23 10:05:52

Python歷史

2021-09-28 10:59:53

MYSQLPerformance 內存管理

2025-06-16 09:46:06

2018-03-07 13:21:26

RocksDB數(shù)據(jù)存儲

2022-08-31 08:04:08

Ceph配置選項

2021-12-11 08:05:12

FlinkRocksDB數(shù)據(jù)

2010-01-08 14:06:49

JSON 形式

2010-03-01 16:48:02

Python模塊

2010-06-01 11:22:30

SVN合并跟蹤

2010-05-24 16:58:44

SVN安裝

2011-07-21 09:42:27

Objective-C 內存 Autoreleas
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费中文字幕 | 精品视频一区二区在线观看 | 欧美a在线| 亚洲韩国精品 | 亚洲欧美中文日韩在线v日本 | 久久高清国产视频 | av在线一区二区 | 亚洲视频在线播放 | 天天av网 | 成人片在线看 | 国产精品一区二区三区在线 | 午夜影院网站 | 国产精品综合视频 | 亚洲精品视频三区 | 日韩一区二区视频 | 91免费电影| 欧美综合一区 | 亚洲精品一区二三区不卡 | 国产视频1 | 亚洲第一网站 | 亚洲欧美综合精品久久成人 | 久草高清视频 | 亚洲国产成人精品女人久久久 | 亚洲国产午夜 | av一区二区三区四区 | 一区二区三区国产精品 | 国产福利视频 | 欧美女优在线观看 | 日韩毛片在线免费观看 | 亚洲精品亚洲人成人网 | 久久精品网 | 亚洲综合在线一区二区 | 国产成都精品91一区二区三 | 午夜精品一区二区三区免费视频 | 亚洲欧美中文字幕在线观看 | 色欧美综合| 日本精品一区二区三区在线观看视频 | 日韩www视频 | 黄网站色大毛片 | 日韩高清中文字幕 | 免费黄色的网站 |