理解Redis內(nèi)存消耗,管理和優(yōu)化。
1. 內(nèi)存消耗
1.1 內(nèi)存使用統(tǒng)計(jì)
通過info memory
命令獲取內(nèi)存相關(guān)指標(biāo),重點(diǎn)指標(biāo):
used_memory_rss //操作系統(tǒng)角度Redis進(jìn)程占用的物理內(nèi)存總量
used_memory //Redis內(nèi)部存儲的所有數(shù)據(jù)內(nèi)存占用量
mem_fragmentation_ratio //內(nèi)存碎片率 >1時(shí)說明多出的內(nèi)存被內(nèi)存碎片消耗,<1時(shí)則要注意操作系統(tǒng)swap到硬盤
1.2 內(nèi)存消耗劃分
Redis內(nèi)存消耗劃分.jpg
- 對象內(nèi)存:存儲用戶所有key-value數(shù)據(jù)
- 緩沖內(nèi)存:客戶端緩沖,復(fù)制積壓緩沖區(qū),AOF緩沖區(qū)
- 內(nèi)存碎片:默認(rèn)內(nèi)存分配器:jemalloc
1.3 子進(jìn)程內(nèi)存消耗
- Redis產(chǎn)生的子進(jìn)程并不需要1倍的父進(jìn)程內(nèi)存(copy-on-write),實(shí)際消耗根據(jù)寫入命令量決定
- 需要設(shè)置
sysctl vm.overcommit_memory=1
允許內(nèi)核可以分配所有物理內(nèi)存,放置fork失敗 - 排查當(dāng)前系統(tǒng)是否開啟THP,建議關(guān)閉,防止內(nèi)存過度消耗
2. 內(nèi)存管理
2.1 設(shè)置內(nèi)存上限
- 用于緩存場景,超出上限時(shí)使用LRU釋放空間
- 防止所用內(nèi)存超過服務(wù)器物理內(nèi)存
2.2 動態(tài)調(diào)整內(nèi)存上限
config set maxmemory
動態(tài)修改內(nèi)存,伸縮配置
2.3 內(nèi)存回收策略
- 刪除到達(dá)過期時(shí)間的鍵對象:惰性刪除(客戶端讀取時(shí)檢查刪除)/定時(shí)任務(wù)刪除
- 內(nèi)存溢出控制策略:
- noeviction:默認(rèn),拒絕寫入
- volatile-lru:LRU刪除超時(shí)鍵
- allkeys-lru:LRU刪除所有鍵
- allkeys-random:隨機(jī)刪除所有鍵
- volatile-random:隨機(jī)刪除過期鍵
- volatile-ttl:刪除最近將要過期數(shù)據(jù)
注意:頻繁執(zhí)行回收內(nèi)存成本很高,如果有從節(jié)點(diǎn)會同步,導(dǎo)致寫放大
3. 內(nèi)存優(yōu)化
3.1 redisObject對象
redisObject內(nèi)部結(jié)構(gòu).jpg
- type:數(shù)據(jù)類型
- encoding:內(nèi)部編碼類型
- lru:最后一次被訪問的時(shí)間
- refcount字段:記錄當(dāng)前對象被引用的次數(shù)
- *ptr字段:與對象的數(shù)據(jù)內(nèi)容相關(guān)
3.2 縮減鍵值對象
降低Redis內(nèi)存使用最直接的方法:縮減key和value的長度
選擇高效的序列化工具
3.3 共享對象池
共享對象池是指Redis內(nèi)部維護(hù)[0-9999]整數(shù)對象池。創(chuàng)建大量的整數(shù)類型redisObject存在內(nèi)存開銷。
使用共享對象池,相同的數(shù)據(jù)內(nèi)存使用降低30%以上。
3.4 字符串優(yōu)化
Redis有自己內(nèi)部的動態(tài)字符串:
字符串結(jié)構(gòu)體SDS.jpg
由于預(yù)分配機(jī)制,同樣的數(shù)據(jù)追加后內(nèi)存消耗非常嚴(yán)重。(追加后預(yù)分配一倍容量)
字符串重構(gòu):對json這種,可以使用hash這樣的二級結(jié)構(gòu)來饑餓省內(nèi)存,支持字段的部分讀取修改
3.5 編碼優(yōu)化
不同編碼實(shí)現(xiàn)效率和空間的平衡
編碼類型轉(zhuǎn)換過程不可逆,只能從小內(nèi)存編碼向大內(nèi)存編碼轉(zhuǎn)換。
3.6 控制鍵的數(shù)量
hash結(jié)構(gòu)降低鍵數(shù)量分析
- 根據(jù)鍵規(guī)模在客戶端通過分組映射到一組hash對象中
- hash的field可用于記錄原始key字符串
- hash的value保存原始值結(jié)構(gòu)
hash鍵和field鍵的設(shè)計(jì):
- 鍵的離散度高時(shí),按照字符串位截取
- 鍵離散度低,用哈希算法打散鍵,哈希field存儲鍵的原始值
- 盡量減少hash鍵和field的長度,如使用部分鍵內(nèi)容