溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Redis壓縮列表的示例分析

發(fā)布時(shí)間:2020-12-03 11:37:09 來(lái)源:億速云 閱讀:139 作者:小新 欄目:MySQL數(shù)據(jù)庫(kù)

這篇文章主要介紹了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)的格式:

Redis壓縮列表的示例分析

每一個(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)度

Redis壓縮列表的示例分析

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í)!

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI