您好,登錄后才能下訂單哦!
這篇文章主要介紹了Redis壓縮列表的示例分析,具有一定借鑒價(jià)值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
此篇文章是主要介紹Redis在數(shù)據(jù)存儲(chǔ)方面的其中一種方式,壓縮列表。
本文會(huì)介紹
1、壓縮列表(ziplist)的使用場(chǎng)景
2.如何達(dá)到節(jié)約內(nèi)存的效果?
3.壓縮列表的存儲(chǔ)格式
4. 連鎖更新的問(wèn)題
5. conf文件配置。
在實(shí)踐上的操作主要是對(duì)conf配置文件進(jìn)行配置,具體上沒(méi)有確切的一個(gè)值,更多是經(jīng)驗(yàn)值。也有的項(xiàng)目會(huì)直接使用原本的默認(rèn)值。此篇對(duì)于更好地理解一個(gè)數(shù)據(jù)庫(kù)底層的存儲(chǔ)邏輯會(huì)有一點(diǎn)幫助。修學(xué)儲(chǔ)能,既要博,也要淵。希望這篇文章對(duì)同樣也是在學(xué)習(xí)Redis的各位同伴有點(diǎn)用。(推薦教程:Redis教程)
一、壓縮列表(ziplist)的使用場(chǎng)景:
Redis為了優(yōu)化數(shù)據(jù)存儲(chǔ),節(jié)約內(nèi)存,在列表、字典(哈希鍵)和有序集合的底層實(shí)現(xiàn)了使用壓縮列表這一優(yōu)化方案。
例如,假如一個(gè)哈希鍵里面存儲(chǔ)的字符串比較短,那么Redis就會(huì)將它用壓縮列表的格式去存儲(chǔ),即轉(zhuǎn)換為字節(jié)數(shù)組存儲(chǔ)。而一個(gè)哈希鍵內(nèi)部存儲(chǔ)的整數(shù)值比較小,同樣也會(huì)把它存儲(chǔ)為壓縮列表的一個(gè)節(jié)點(diǎn)。同理,列表鍵的對(duì)小數(shù)據(jù)的存儲(chǔ)跟哈希鍵的操作類似。
如此說(shuō)來(lái),壓縮列表并不是開(kāi)發(fā)者可以直接調(diào)用的Redis中的一種存儲(chǔ)數(shù)據(jù)結(jié)構(gòu),而是Redis中為優(yōu)化數(shù)據(jù)存儲(chǔ)而在底層做的一項(xiàng)努力。理解好這點(diǎn)還是比較重要的。
二、如何達(dá)到節(jié)約內(nèi)存的效果?
壓縮列表是一種序列化的數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)的功能是將一系列數(shù)據(jù)與其編碼信息存儲(chǔ)在一塊連續(xù)的內(nèi)存區(qū)域,這塊內(nèi)存物理上是連續(xù)的。但邏輯上被分為多個(gè)組成部分,即節(jié)點(diǎn)。目的是為了在一定可控的時(shí)間復(fù)雜度條件下盡可能的減少不必要的內(nèi)存開(kāi)銷,從而達(dá)到節(jié)省內(nèi)存的效果。需要理解是怎么達(dá)到節(jié)約內(nèi)存作用的,還需要去了解壓縮列表的存儲(chǔ)格式。
三、壓縮列表的存儲(chǔ)格式:
壓縮列表(ziplist)是Redis列表鍵、哈希鍵和有序集合鍵的底層實(shí)現(xiàn)之一,其實(shí)質(zhì)是一種序列化的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)。有別于普通情況下,Redis用雙端鏈表表示列表,使用散列表表示哈希鍵,用散列表+跳躍表表示有序集合。當(dāng)一個(gè)列表或者哈希字典/有序集合只包含很少內(nèi)容,并且每一個(gè)列表項(xiàng)或者哈希項(xiàng)/有序集合項(xiàng)如果是小整數(shù),或者比較短的字符串。那么Redis就會(huì)用壓縮列表來(lái)做底層的實(shí)現(xiàn)。
壓縮列表由一系列經(jīng)Redis特殊編碼的連續(xù)內(nèi)存塊組成,每一個(gè)內(nèi)存塊稱為一個(gè)節(jié)點(diǎn)(entry),而一個(gè)壓縮列表可以包含很多個(gè)節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)格式可以是字節(jié)數(shù)組(中文字符串等都會(huì)轉(zhuǎn)換為字節(jié)數(shù)組)或者整數(shù)值。
字節(jié)數(shù)組的長(zhǎng)度可以是以下的其中一種:
1. 長(zhǎng)度小于等于63字節(jié)(2的6次方)
2. 長(zhǎng)度小于等于16383字節(jié)(2的14次方)
3. 長(zhǎng)度小于等于4294967295字節(jié)(2的32次方)
整數(shù)值可能是以下六種中的其中一種:
1. 4位長(zhǎng),介于0-12之間的無(wú)符號(hào)整數(shù)
2. 1字節(jié)長(zhǎng)的有符號(hào)整數(shù)
3. 3字節(jié)長(zhǎng)的有符號(hào)整數(shù)
4. int16_t類型整數(shù)
5. int32_類型整數(shù)
6. int64_t類型整數(shù)
普通存儲(chǔ)格式下和壓縮列表存儲(chǔ)格式下的不同點(diǎn):
列表存儲(chǔ)結(jié)構(gòu)典型的為雙端鏈表,每一個(gè)值都是用一個(gè)節(jié)點(diǎn)來(lái)表示,每個(gè)節(jié)點(diǎn)都會(huì)有指向前一個(gè)節(jié)點(diǎn)和后一個(gè)節(jié)點(diǎn)的指針,以及指向節(jié)點(diǎn)包含的字符串值的指針。而字符串值又分為3個(gè)部分存儲(chǔ),第一部分存儲(chǔ)字符串長(zhǎng)度,第二部分存儲(chǔ)字符串值中剩余可用的字節(jié)量,第三部分存儲(chǔ)的則是字符串?dāng)?shù)據(jù)本身。所以一個(gè)節(jié)點(diǎn)往往都需要存儲(chǔ)3個(gè)指針、2個(gè)記錄字符串信息的整數(shù)、字符串本省和一個(gè)額外的字節(jié)??傮w上額外的開(kāi)銷是很大的(21字節(jié))。
壓縮列表節(jié)點(diǎn)的格式:
每一個(gè)節(jié)點(diǎn)都有previous_entry_length,encoding,content三個(gè)部分組成,在遍歷壓縮列表的時(shí)候是從后往前遍歷的。
1. previous_entry_length記錄了前一個(gè)節(jié)點(diǎn)的長(zhǎng)度,只要用當(dāng)前指針減去這個(gè)值就可以達(dá)到前一個(gè)節(jié)點(diǎn)的起始地址。
2. encoding記錄了節(jié)點(diǎn)content屬性所保存數(shù)據(jù)的類型和長(zhǎng)度
3. content記錄了一個(gè)節(jié)點(diǎn)的值
顯然壓縮列表這種方式節(jié)約了不少存儲(chǔ)空間。但同時(shí)也會(huì)引發(fā)下面的問(wèn)題。
四、連鎖更新的問(wèn)題:
一般而言如果前一個(gè)節(jié)點(diǎn)的整體長(zhǎng)度小于254字節(jié),previous_entry_length屬性只需要1個(gè)字節(jié)的空間來(lái)保存這個(gè)長(zhǎng)度值。而當(dāng)前一個(gè)節(jié)點(diǎn)大于254字節(jié)的時(shí)候,previous_entry_length屬性要用5個(gè)字節(jié)長(zhǎng)的空間來(lái)記錄長(zhǎng)度值。
當(dāng)長(zhǎng)度為254字節(jié)左右的節(jié)點(diǎn)前插入一個(gè)新的節(jié)點(diǎn)的時(shí)候,需要增加previous_entry_length來(lái)記錄這個(gè)節(jié)點(diǎn)到新節(jié)點(diǎn)的偏移量。這個(gè)時(shí)候,這個(gè)節(jié)點(diǎn)的長(zhǎng)度肯定就大于254字節(jié)了。所以這個(gè)節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)就不能只用一個(gè)字節(jié)的previous_entry_length來(lái)記錄這個(gè)節(jié)點(diǎn)的信息了,而是需要5個(gè)字節(jié)來(lái)記錄。如果連續(xù)多個(gè)節(jié)點(diǎn)的長(zhǎng)度都為254字節(jié)左右,在其中的某一個(gè)節(jié)點(diǎn)前/后發(fā)生節(jié)點(diǎn)的插入和刪除(刪除的推理與插入相反,原本用5字節(jié)記錄前一節(jié)點(diǎn)的可能變?yōu)?字節(jié)),都可能引發(fā)連鎖的更新,顯然,這樣對(duì)系統(tǒng)地運(yùn)行效率是很不利的。不過(guò),在實(shí)際應(yīng)用中這種情況還是比較少發(fā)生的。
而雙端鏈表在節(jié)點(diǎn)的更新、增加和刪除上顯得就會(huì)“輕松”很多了。 因?yàn)槊恳粋€(gè)節(jié)點(diǎn)存儲(chǔ)的信息都是相對(duì)獨(dú)立的。
實(shí)踐意義:
要預(yù)估一個(gè)節(jié)點(diǎn)大概占據(jù)多少字節(jié)的存儲(chǔ)空間,適當(dāng)?shù)卣{(diào)整字段的存儲(chǔ)格式而不要使存儲(chǔ)的字段值占據(jù)存儲(chǔ)空間落在254字節(jié)(除去encoding屬性和previous_entry_length屬性)左右。
Redis中查看字符串和哈希鍵值的長(zhǎng)度相關(guān)命令:
1. 查詢字符串鍵對(duì)應(yīng)的值長(zhǎng)度
命令:
Strlen
例如:
127.0.0.1:6379> strlen m_name
(integer) 8
2. 查詢哈希鍵某一個(gè)域長(zhǎng)度
命令:
Hstrlen
例如:
127.0.0.1:6379> hstrlen good_list good_list1
(integer) 226
五、Conf文件配置:
通過(guò)修改配置文件,可以控制是否使用壓縮列表存儲(chǔ)相關(guān)鍵的最大元素個(gè)數(shù)和最大元素的大小
Conf文件中的配置:
1.
[] -max-ziplist-entries : 表示對(duì)于鍵的最大元素個(gè)數(shù),即一個(gè)鍵中在該指定值下的數(shù)量的節(jié)點(diǎn)個(gè)數(shù)都會(huì)用壓縮列表來(lái)儲(chǔ)存
[] -max-ziplist-value :表示壓縮列表中每個(gè)節(jié)點(diǎn)的最大體積是多少字節(jié)
實(shí)際使用中,一個(gè)列表鍵/哈希鍵的某一個(gè)元素往往存儲(chǔ)著比較大的信息量,會(huì)大于64字節(jié),所以配置時(shí)很有可能會(huì)比64大,同時(shí)考慮到實(shí)際存儲(chǔ)數(shù)據(jù)的容量大小以及上面談到的previous_entry_length的大小問(wèn)題,對(duì)[] -max-ziplist-value進(jìn)行合理的配置。
配置文件內(nèi)容:
############## ADVANCED CONFIG ########################## 哈希鍵 # Hashes are encoded using a memory efficient data structure when they have a # small number of entries, and the biggest entry does not exceed a given # threshold. These thresholds can be configured using the following directives. hash-max-ziplist-entries 512 hash-max-ziplist-value 64 有序集合鍵 # Similarly to hashes and lists, sorted sets are also specially encoded in # order to save a lot of space. This encoding is only used when the length and # elements of a sorted set are below the following limits: zset-max-ziplist-entries 128 zset-max-ziplist-value 64 列表鍵,比較特殊,直接使用制定大小kb字節(jié)數(shù)表示(有些conf文件的列表鍵與hash鍵的表達(dá)式?jīng)]太大區(qū)別) # Lists are also encoded in a special way to save a lot of space. # The number of entries allowed per internal list node can be specified # as a fixed maximum size or a maximum number of elements. # For a fixed maximum size, use -5 through -1, meaning: # -5: max size: 64 Kb <-- not recommended for normal workloads # -4: max size: 32 Kb <-- not recommended # -3: max size: 16 Kb <-- probably not recommended # -2: max size: 8 Kb <-- good # -1: max size: 4 Kb <-- good # Positive numbers mean store up to _exactly_ that number of elements # per list node. # The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), # but if your use case is unique, adjust the settings as necessary. list-max-ziplist-size -2
案例:
修改配置前使用默認(rèn)配置:
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
127.0.0.1:6379> hstrlen good_list good_list1
(integer) 226
127.0.0.1:6379> object encoding good_list
"hashtable"
修改配置:
hash-max-ziplist-entries 512
hash-max-ziplist-value 254
注意:修改配置后需要重啟服務(wù)器
127.0.0.1:6379> hstrlen good_list good_list1
(integer) 226
127.0.0.1:6379> object encoding good_list
"ziplist"
可以看到存儲(chǔ)方式已將變?yōu)閦iplist
較官方的壓力測(cè)試和指導(dǎo)建議:
當(dāng)一個(gè)壓縮列表的元素?cái)?shù)量上升到幾千(實(shí)際使用可能遠(yuǎn)小于這個(gè)值)的時(shí)候,壓縮列表的性能可能會(huì)下降,因?yàn)镽edis在操作這種結(jié)構(gòu)的時(shí)候,編解碼會(huì)出現(xiàn)一定的壓力。
壓縮列表的長(zhǎng)度限制在500-2000之內(nèi),每個(gè)元素體積限制在128字節(jié)或以下,壓縮列表的的性能都會(huì)處于合理范圍之內(nèi)。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享Redis壓縮列表的示例分析內(nèi)容對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問(wèn)題就找億速云,詳細(xì)的解決方法等著你來(lái)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。