Redis开发与运维之第八章理解内存(五)
insert編碼
是集合(set)的類型編碼的一種,內(nèi)部表現(xiàn)為存儲(chǔ)有序、不重復(fù)的整數(shù)集。當(dāng)集合只包含整數(shù)且長(zhǎng)度不超過set-max-intset-entries 配置時(shí)被啟用。執(zhí)行以下命令查看intset表現(xiàn):
redis> sadd set:test 3 4 2 6 8 9 2 (integer) 6 redis> object encoding set:test "intset" redis> smembers set:test "2" "3" "4" "6" "8" "9" redis> config set set-max-intset-entries 6 OK redis> sadd set:test 5 "hashtable" redis> smembers set:test "8" "3" "5" "9" "4" "2" "6"以上命令可以看出intset對(duì)寫入整數(shù)進(jìn)行排序,通過O(logn)時(shí)間復(fù)雜度實(shí)現(xiàn)查找和去重操作,intset編碼結(jié)構(gòu)如圖所示:
??
字段結(jié)構(gòu)含義:
1. encoding:整數(shù)表示類型,根據(jù)結(jié)合內(nèi)最長(zhǎng)整數(shù)值確定類型,整數(shù)類型劃分為三種,int-16/int-32/int-64
2. length:表示集合元素個(gè)數(shù)。
3. contents: 整數(shù)數(shù)組、按從小到大順序保存。
intset保存的整數(shù)類型根據(jù)長(zhǎng)度劃分,當(dāng)保存的整數(shù)超出當(dāng)前類型時(shí),將會(huì)觸發(fā)自動(dòng)升級(jí)操作且升級(jí)后不再做回退。
升級(jí)操作將會(huì)導(dǎo)致重新申請(qǐng)內(nèi)存空間,把原有數(shù)據(jù)按轉(zhuǎn)換類型后拷貝到新數(shù)組中。
控制鍵的數(shù)量
當(dāng)使用redis存儲(chǔ)大量數(shù)據(jù)時(shí),通常會(huì)存在大量鍵,過多的鍵同樣會(huì)消耗大量?jī)?nèi)存。Redis本質(zhì)是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù)器,它為我們提供多種數(shù)據(jù)結(jié)構(gòu),如hash、list、set、zset等。使用Redis時(shí)不要進(jìn)入一個(gè)誤區(qū),大量使用get/set/這樣的API,把redis當(dāng)錯(cuò)memcached使用。
對(duì)于存儲(chǔ)相同的數(shù)據(jù)內(nèi)容利用Redis的數(shù)據(jù)結(jié)構(gòu)降低外層鍵的數(shù)量,也可以節(jié)省大量?jī)?nèi)存。如圖所示,通過在客戶端預(yù)估鍵規(guī)模,把大量鍵分組映射到多個(gè)hash結(jié)構(gòu)中減低鍵的數(shù)量。
?hash結(jié)構(gòu)降低鍵數(shù)量分析:
1. 根據(jù)鍵規(guī)模在客戶端通過分組映射到一組hash對(duì)象中,如存在100萬個(gè)鍵,可以映射到1000個(gè)hash中,每個(gè)hash保存1000個(gè)元素。
2. hash的field可用于記錄原始key字符串,方便哈希查找。
3. hash的value保存原始值對(duì)象,確保不要超過hash-max-ziplist-value限制。
同樣的數(shù)據(jù)使用ziplist編碼的hash類型存儲(chǔ)比string類型節(jié)約內(nèi)存。
節(jié)省內(nèi)存量隨著value空間的減少越來越明顯。
hash-ziplist類型比string類型寫入耗時(shí),但隨著value空間的減少,耗時(shí)逐漸降低。
使用hash重構(gòu)后節(jié)省內(nèi)存量效果非常明顯,特別對(duì)于存儲(chǔ)小對(duì)象的場(chǎng)景,內(nèi)存只有不到原來的1/5 。下面分析這種內(nèi)存優(yōu)化技巧的關(guān)鍵點(diǎn);
1. hash類型節(jié)省內(nèi)存的原理是使用ziplist編碼,如果使用hashtable編碼方式反而會(huì)增加內(nèi)存消耗。
2? ziplist長(zhǎng)度需要控制在1000以內(nèi),否則由于存儲(chǔ)操作時(shí)間復(fù)雜度在O(n) 到O(n2)之間,長(zhǎng)列表會(huì)導(dǎo)致CPU消耗嚴(yán)重,得不償失。
3. ziplist適合存儲(chǔ)小對(duì)象,對(duì)于大對(duì)象不但內(nèi)存優(yōu)化效果不明顯還會(huì)增加命令操作耗時(shí)。
4. 需要預(yù)估鍵的規(guī)模,從而確定每個(gè)hash結(jié)構(gòu)需要存儲(chǔ)的元素?cái)?shù)量
5. 根據(jù)hash長(zhǎng)度和元素大小,調(diào)整hash-max-ziplist-entries和hash-max-ziplist-value參數(shù),確保hash類型使用ziplist編碼
關(guān)于hash鍵和field鍵的設(shè)計(jì):
1. 當(dāng)鍵離散度較高時(shí),可以按字符串位截取,把后三位作為哈希的field,之前部分作為哈希的鍵。
如:key=1948480哈希key=group:hash:1948,哈希field=480。
2.?當(dāng)鍵離散度較低時(shí),可以使用哈希算法打散鍵,
如:使用crc32(key)&10000函數(shù)把所有的鍵映射到“0-9999”整數(shù)范圍內(nèi),哈希field存儲(chǔ)鍵的原始值。
3.?盡量減少hash鍵和field的長(zhǎng)度,如使用部分鍵內(nèi)容
使用hash結(jié)構(gòu)控制鍵的規(guī)模雖然可以大幅降低內(nèi)存,但同樣會(huì)帶來問題,需要提前做好規(guī)避處理
1. 客戶端需要預(yù)估鍵的規(guī)模并設(shè)計(jì)hash分組規(guī)則,加重客戶端開發(fā)成本。
2.?hash重構(gòu)后所有的鍵無法再使用超時(shí)(expire)和LRU淘汰機(jī)制自動(dòng)刪除,需要手動(dòng)維護(hù)刪除
3.?對(duì)于大對(duì)象,如1KB以上的對(duì)象,使用hash-ziplist結(jié)構(gòu)控制鍵數(shù)量反而得不償失
4.?對(duì)于大量小對(duì)象的存儲(chǔ)場(chǎng)景,非常適合使用ziplist編碼的hash類型控制鍵的規(guī)模來降低內(nèi)存
使用ziplist+hash優(yōu)化keys后,如果想使用超時(shí)刪除功能,開發(fā)人員可以存儲(chǔ)每個(gè)對(duì)象寫入的時(shí)間,再通過定時(shí)任務(wù)使用hscan命令掃描數(shù)據(jù),找出hash內(nèi)超時(shí)的數(shù)據(jù)項(xiàng)刪除即可
?
?
總結(jié)
以上是生活随笔為你收集整理的Redis开发与运维之第八章理解内存(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 绝对定位和浮动的区别和运用
- 下一篇: mysql: 模糊查询 feild li