網(wǎng)站首頁 編程語言 正文
Redis內(nèi)存碎片處理
不知道我們?cè)趫?zhí)行刪除操作時(shí)有沒有注意過這樣一個(gè)現(xiàn)象,刪除一些bigkey后內(nèi)存分配器分配的容量并沒有減少,實(shí)際容量減少了,這是為什么呢?演示如下
模擬bigkey刪除
創(chuàng)建生成bigkey的腳本文件createdata.sh
#!/bin/bash cd /opt/redis/redis-6.0.6/bin/ for i in {1..10000} do echo "key${i} ${i}" redis-cli hset obj key${i} ${i} done
賦執(zhí)行權(quán)限
[root@zzf993 redis-6.0.6]# chmod +x createdata.sh ### 執(zhí)行權(quán)限如果分不清可以賦予所有權(quán)限 [root@zzf993 redis-6.0.6]# chmod 777 createdata.sh
執(zhí)行createdata.sh腳本,等待執(zhí)行完畢
查看內(nèi)存容量
########## 執(zhí)行createdata.sh腳本前的內(nèi)存容量 127.0.0.1:6379> info memory # Memory used_memory:864192 used_memory_human:843.94K used_memory_rss:4681728 used_memory_rss_human:4.46M ########## 執(zhí)行createdata.sh腳本后的內(nèi)存容量 # Memory used_memory:1565384 used_memory_human:1.49M used_memory_rss:5992448 used_memory_rss_human:5.71M
將key為obj的鍵值刪除后,查看內(nèi)存容量
127.0.0.1:6379> info memory # Memory used_memory:896416 used_memory_human:875.41K used_memory_rss:5746688 used_memory_rss_human:5.48M
刪除bigkey后used_memory_rss波動(dòng)很小,而used_memory波動(dòng)很大,因?yàn)閡sed_memory_rss是系統(tǒng)向redis分配的內(nèi)存空間,而used_memory是redis實(shí)際使用的內(nèi)存空間,上述實(shí)驗(yàn)表明redis刪除鍵值后并沒有馬上的將內(nèi)存空間回收,所以即使刪除了一些bigkey的鍵值,redis占用的空間依然還是那么大,這些空間后續(xù)還會(huì)不會(huì)使用呢?這個(gè)需要分情況
如果刪除的鍵值空間是連續(xù)的那么后續(xù)新增鍵值還是可以用來存儲(chǔ)數(shù)據(jù)。
如果刪除的鍵值空間不連續(xù)那么這就有可能形成的內(nèi)存碎片。
那么這些內(nèi)存碎片能不能重復(fù)利用呢?我們可以接著往下面思考。
什么是內(nèi)存碎片
內(nèi)存碎片一句話描述就是有那么多內(nèi)存但是放不下那么多數(shù)據(jù),我們以高鐵買票為例解釋,張三、李四、王五去訂票這三個(gè)人想訂連在一起的三個(gè)座位,而最近一趟車有100個(gè)座位,已售97個(gè),剩余三個(gè)座位并不相鄰,那么他們?nèi)齻€(gè)只能改換下一趟高鐵,因?yàn)樽徊环纤麄兊念A(yù)期,那么這趟車就有三個(gè)座位空閑,這就是座位碎片。
將碎片概念放到內(nèi)存中就是連續(xù)空閑的空間放不下那么多數(shù)據(jù),如下圖,需要向內(nèi)存中放入一個(gè)3字節(jié)的數(shù)據(jù),雖然內(nèi)存中存在3字節(jié)空閑的內(nèi)存,但空閑內(nèi)存不連續(xù)所以無法存放,這就是內(nèi)存碎片
內(nèi)存碎片如何產(chǎn)生
內(nèi)存分配器
在Redis中有多種內(nèi)存分配策略如libc、jemalloc、tcmalloc,默認(rèn)使用jemalloc,操作系統(tǒng)的內(nèi)存分配器根據(jù)這些分配策略分配內(nèi)存,但是內(nèi)存分配器無法做到按需分配,一般按照固定大小分配,以默認(rèn)分配策略jemalloc為例,一般按照2的整數(shù)次冪分配如2、4、8、16、32等等,如redis申請(qǐng)一個(gè)6字節(jié)的內(nèi)存,操作系統(tǒng)就會(huì)分配一個(gè)8字節(jié)的內(nèi)存給redis使用,那么多出來的2個(gè)字節(jié)空間,如果后續(xù)沒有其它操作,那么這2個(gè)字節(jié)就是內(nèi)存碎片。
那這樣分配是不是完全沒有優(yōu)勢(shì)呢?顯然不是,如redis第一次向操作系統(tǒng)申請(qǐng)了24字節(jié)的內(nèi)存,分配器給redis分配了32字節(jié)的空間,當(dāng)下次redis寫入需要8字節(jié)以內(nèi)的空間就不需要再次向操作系統(tǒng)申請(qǐng)了,現(xiàn)有的內(nèi)存空間完全可以滿足要求,所以這樣的分配方式可以減少向操作系統(tǒng)申請(qǐng)空間分配。
鍵值大小不同
因?yàn)閮?nèi)存分配器不是按需分配,而不同的鍵值大小也就會(huì)給redis帶來不一樣的碎片,如鍵值key1占用內(nèi)存5個(gè)字節(jié),鍵值key2占用內(nèi)存7個(gè)字節(jié),向操作系統(tǒng)申請(qǐng)時(shí)都會(huì)給分配8個(gè)字節(jié),key1鍵值的碎片就是3個(gè)字節(jié),而key2鍵值的碎片就是1個(gè)字節(jié)。
鍵值的操作
鍵值的修改、刪除也會(huì)造成碎片如下所示
碎片信息如何查看
碎片信息redis提供了info memory
命令給用戶監(jiān)控碎片情況
127.0.0.1:6379> info memory # Memory used_memory:917256 used_memory_human:895.76K used_memory_rss:5488640 used_memory_rss_human:5.23M ....... mem_fragmentation_ratio:6.26
內(nèi)存信息中mem_fragmentation_ratio指標(biāo)就是內(nèi)存的碎片率,碎片率計(jì)算如下
mem_fragmentation_ratio = used_memory_rss/used_memory
used_memory_rss:表示是由操作系統(tǒng)分配的內(nèi)存大小。
used_memory:表示Redis實(shí)例占用的內(nèi)存大小。
如redis向操作系統(tǒng)申請(qǐng)100字節(jié)的內(nèi)存這就是used_memory,操作系統(tǒng)為redis分配128字節(jié)的內(nèi)存這就是used_memory_rss,碎片率就是mem_fragmentation_ratio=1.28。
當(dāng)mem_fragmentation_ratio<=1.5時(shí),因?yàn)椴僮飨到y(tǒng)的分配器緣故碎片率避免不了,而且鍵值的修改,刪除也會(huì)導(dǎo)致碎片率,所以這算是一個(gè)正常范疇。
當(dāng)mem_fragmentation_ratio>1.5時(shí),相當(dāng)于碎片率超過了實(shí)際占用內(nèi)存的50%,這就造成了內(nèi)存的浪費(fèi),需要采取一些措施降低碎片率。
注意:如果線上數(shù)據(jù)顯示mem_fragmentation_ratio<1,證明碎片率低,是不是碎片率越低就越好呢?顯然不是,碎片率小于1說明used_memory_rss操作系統(tǒng)分配的內(nèi)存少了,也就是說Redis能使用的物理內(nèi)存不夠了,這就會(huì)觸發(fā)swap,將內(nèi)存的數(shù)據(jù)換到磁盤中,后續(xù)客戶端如果訪問了磁盤中的數(shù)據(jù)將產(chǎn)生延遲。
碎片率如何降低
當(dāng)Redis版本是4.0以下,那么我們只能通過重啟實(shí)例解決問題,但需要注意的是重啟會(huì)有部分?jǐn)?shù)據(jù)丟失,即使開啟了持久化。
當(dāng)Redis版本是4.0以上,我們可以通過配置activedefrag yes
自動(dòng)碎片清理來完成,簡單形容就是零換整的思想,將空閑內(nèi)存碎片合并到一起,形成一片連續(xù)的空間,如下所示
不過萬事都有兩面性,開啟自動(dòng)碎片清理后,會(huì)阻塞主線程,所以需要注意清理參數(shù)控制,參數(shù)如下
active-defrag-ignore-bytes 100mb:碎片清理的最小碎片內(nèi)存,碎片內(nèi)存到達(dá)100mb后開始清理。
active-defrag-threshold-lower 10:表示內(nèi)存碎片空間占分配給redis總空間的10%開始清理和active-defrag-ignore-bytes必須同時(shí)滿足,有一個(gè)不滿足停止自動(dòng)清理。
active-defrag-cycle-min 25:表示碎片清理占用CPU最少的比例,保證碎片清理可以正常運(yùn)行。
active-defrag-cycle-max 75:表示碎片清理占用CPU最大的比例,不能讓碎片清理影響業(yè)務(wù)正常處理。
如果碎片清理期間阻塞了主線程的業(yè)務(wù)處理,一般需要將active-defrag-cycle-max占用CPU的最大比例調(diào)小。
總結(jié)
原文鏈接:https://juejin.cn/post/7102780689497456671
相關(guān)推薦
- 2023-06-04 Android?ButterKnife依賴注入框架使用教程_Android
- 2022-10-06 Android開發(fā)Jetpack組件Room使用講解_Android
- 2022-05-03 python實(shí)現(xiàn)跨進(jìn)程(跨py文件)通信示例_python
- 2023-02-23 Python創(chuàng)建7種不同的文件格式的方法總結(jié)_python
- 2022-11-03 python如何判斷文件存在方式_python
- 2022-01-15 Meteor 項(xiàng)目部署至服務(wù)器(windows)
- 2022-12-11 Redhat持久化日志實(shí)戰(zhàn)示例詳解_相關(guān)技巧
- 2022-09-14 Android?實(shí)現(xiàn)卡片堆疊錢包管理動(dòng)畫效果_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支