得物面試:Redis 內(nèi)存碎片是什么?如何清理?
共 4458字,需瀏覽 9分鐘
·
2024-04-19 09:03
JavaGuide官方網(wǎng)站:javaguide.cn
這是一道不是特別高頻但很重要的 Redis 面試題,屬于 Redis 性能優(yōu)化的范疇。
Redis 內(nèi)存碎片相關(guān)的問題在得物、美團(tuán)、阿里、字節(jié)、攜程等公司的后端面試中都曾出現(xiàn)過,還是建議認(rèn)真準(zhǔn)備一下。即使不是準(zhǔn)備面試,日常開發(fā)也是能夠用到的!
什么是內(nèi)存碎片?
你可以將內(nèi)存碎片簡單地理解為那些不可用的空閑內(nèi)存。
舉個(gè)例子:操作系統(tǒng)為你分配了 32 字節(jié)的連續(xù)內(nèi)存空間,而你存儲(chǔ)數(shù)據(jù)實(shí)際只需要使用 24 字節(jié)內(nèi)存空間,那這多余出來的 8 字節(jié)內(nèi)存空間如果后續(xù)沒辦法再被分配存儲(chǔ)其他數(shù)據(jù)的話,就可以被稱為內(nèi)存碎片。
Redis 內(nèi)存碎片雖然不會(huì)影響 Redis 性能,但是會(huì)增加內(nèi)存消耗。
為什么會(huì)有 Redis 內(nèi)存碎片?
Redis 內(nèi)存碎片產(chǎn)生比較常見的 2 個(gè)原因:
1、Redis 存儲(chǔ)數(shù)據(jù)的時(shí)候向操作系統(tǒng)申請(qǐng)的內(nèi)存空間可能會(huì)大于數(shù)據(jù)實(shí)際需要的存儲(chǔ)空間。
以下是這段 Redis 官方的原話:
To store user keys, Redis allocates at most as much memory as the
maxmemorysetting enables (however there are small extra allocations possible).
Redis 使用 zmalloc 方法(Redis 自己實(shí)現(xiàn)的內(nèi)存分配方法)進(jìn)行內(nèi)存分配的時(shí)候,除了要分配 size 大小的內(nèi)存之外,還會(huì)多分配 PREFIX_SIZE 大小的內(nèi)存。
zmalloc 方法源碼如下(源碼地址:https://github.com/antirez/redis-tools/blob/master/zmalloc.c):
void *zmalloc(size_t size) {
// 分配指定大小的內(nèi)存
void *ptr = malloc(size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
另外,Redis 可以使用多種內(nèi)存分配器來分配內(nèi)存( libc、jemalloc、tcmalloc),默認(rèn)使用 jemalloc[1],而 jemalloc 按照一系列固定的大小(8 字節(jié)、16 字節(jié)、32 字節(jié)……)來分配內(nèi)存的。jemalloc 劃分的內(nèi)存單元如下圖所示:
當(dāng)程序申請(qǐng)的內(nèi)存最接近某個(gè)固定值時(shí),jemalloc 會(huì)給它分配相應(yīng)大小的空間,就比如說程序需要申請(qǐng) 17 字節(jié)的內(nèi)存,jemalloc 會(huì)直接給它分配 32 字節(jié)的內(nèi)存,這樣會(huì)導(dǎo)致有 15 字節(jié)內(nèi)存的浪費(fèi)。不過,jemalloc 專門針對(duì)內(nèi)存碎片問題做了優(yōu)化,一般不會(huì)存在過度碎片化的問題。
2、頻繁修改 Redis 中的數(shù)據(jù)也會(huì)產(chǎn)生內(nèi)存碎片。
當(dāng) Redis 中的某個(gè)數(shù)據(jù)刪除時(shí),Redis 通常不會(huì)輕易釋放內(nèi)存給操作系統(tǒng)。
這個(gè)在 Redis 官方文檔中也有對(duì)應(yīng)的原話:
文檔地址:https://redis.io/topics/memory-optimization 。
如何查看 Redis 內(nèi)存碎片的信息?
使用 info memory 命令即可查看 Redis 內(nèi)存相關(guān)的信息。下圖中每個(gè)參數(shù)具體的含義,Redis 官方文檔有詳細(xì)的介紹:https://redis.io/commands/INFO 。
Redis 內(nèi)存碎片率的計(jì)算公式:mem_fragmentation_ratio (內(nèi)存碎片率)= used_memory_rss (操作系統(tǒng)實(shí)際分配給 Redis 的物理內(nèi)存空間大小)/ used_memory(Redis 內(nèi)存分配器為了存儲(chǔ)數(shù)據(jù)實(shí)際申請(qǐng)使用的內(nèi)存空間大小)
也就是說,mem_fragmentation_ratio (內(nèi)存碎片率)的值越大代表內(nèi)存碎片率越嚴(yán)重。
一定不要誤認(rèn)為used_memory_rss 減去 used_memory值就是內(nèi)存碎片的大小!!!這不僅包括內(nèi)存碎片,還包括其他進(jìn)程開銷,以及共享庫、堆棧等的開銷。
很多小伙伴可能要問了:“多大的內(nèi)存碎片率才是需要清理呢?”。
通常情況下,我們認(rèn)為 mem_fragmentation_ratio > 1.5 的話才需要清理內(nèi)存碎片。mem_fragmentation_ratio > 1.5 意味著你使用 Redis 存儲(chǔ)實(shí)際大小 2G 的數(shù)據(jù)需要使用大于 3G 的內(nèi)存。
如果想要快速查看內(nèi)存碎片率的話,你還可以通過下面這個(gè)命令:
> redis-cli -p 6379 info | grep mem_fragmentation_ratio
另外,內(nèi)存碎片率可能存在小于 1 的情況。這種情況我在日常使用中還沒有遇到過,感興趣的小伙伴可以看看這篇文章 故障分析 | Redis 內(nèi)存碎片率太低該怎么辦?- 愛可生開源社區(qū) 。
如何清理 Redis 內(nèi)存碎片?
Redis4.0-RC3 版本以后自帶了內(nèi)存整理,可以避免內(nèi)存碎片率過大的問題。
直接通過 config set 命令將 activedefrag 配置項(xiàng)設(shè)置為 yes 即可。
config set activedefrag yes
具體什么時(shí)候清理需要通過下面兩個(gè)參數(shù)控制:
# 內(nèi)存碎片占用空間達(dá)到 500mb 的時(shí)候開始清理
config set active-defrag-ignore-bytes 500mb
# 內(nèi)存碎片率大于 1.5 的時(shí)候開始清理
config set active-defrag-threshold-lower 50
通過 Redis 自動(dòng)內(nèi)存碎片清理機(jī)制可能會(huì)對(duì) Redis 的性能產(chǎn)生影響,我們可以通過下面兩個(gè)參數(shù)來減少對(duì) Redis 性能的影響:
# 內(nèi)存碎片清理所占用 CPU 時(shí)間的比例不低于 20%
config set active-defrag-cycle-min 20
# 內(nèi)存碎片清理所占用 CPU 時(shí)間的比例不高于 50%
config set active-defrag-cycle-max 50
另外,重啟節(jié)點(diǎn)可以做到內(nèi)存碎片重新整理。如果你采用的是高可用架構(gòu)的 Redis 集群的話,你可以將碎片率過高的主節(jié)點(diǎn)轉(zhuǎn)換為從節(jié)點(diǎn),以便進(jìn)行安全重啟。
文章結(jié)尾,再推薦幾篇 Redis 相關(guān)的高頻面試題解答:
-
這 7 道 Redis 基礎(chǔ)問題,很常見!! -
如何發(fā)現(xiàn) Redis 熱 Key,有哪些解決方案? -
Redis 大 key 有什么危害?如何排查和處理? -
Redis 除了緩存還能做什么?可以做消息隊(duì)列嗎? -
本地緩存和分布式緩存有什么區(qū)別?如何選擇? -
宕機(jī)了,Redis 如何避免數(shù)據(jù)丟失? -
Redis 如何使用批量操作提高效率? -
Redis 八種常用數(shù)據(jù)類型常用命令和應(yīng)用場景 -
Redis 緩存穿透、緩存擊穿、緩存雪崩區(qū)別和解決方案 -
如何實(shí)現(xiàn)緩存預(yù)熱?
參考資料
jemalloc: https://github.com/jemalloc/jemalloc
??推薦:
點(diǎn)擊下方卡片進(jìn)入公眾號(hào)
回復(fù) 「PDF」 即可領(lǐng)取原創(chuàng)PDF技術(shù)面試手冊
回復(fù) 「學(xué)習(xí)路線」 即可獲取4w+字最新版Java學(xué)習(xí)路線
回復(fù) 「開源」 即可獲取優(yōu)質(zhì)Java開源項(xiàng)目合集
免費(fèi)分享無套路,有幫助點(diǎn)個(gè)贊就好!
