摘要
redis是一款著名的key-value內(nèi)存數(shù)據(jù)庫軟件,同時(shí)也是一款卓越的數(shù)據(jù)結(jié)構(gòu)服務(wù)軟件。它支持字符串、列表、哈希表、集合、有序集合五種數(shù)據(jù)結(jié)構(gòu)類型,同時(shí)每種數(shù)據(jù)結(jié)構(gòu)類型針對不同的應(yīng)用場景又支持不同的編碼方式。這篇文章主要介紹壓縮列表編碼,在理解壓縮列表編碼原理的基礎(chǔ)上介紹Redis對壓縮列表的應(yīng)用,最后再對Redis壓縮列表應(yīng)用進(jìn)行分析。
大名ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
Redis壓縮列表原理與應(yīng)用
壓縮列表是一種數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)的功能是將一系列數(shù)據(jù)與其編碼信息存儲在一塊連續(xù)的內(nèi)存區(qū)域,這塊內(nèi)存物理上是連續(xù)的,邏輯上被分為多個(gè)組成部分,其目的是在一定可控的時(shí)間復(fù)雜讀條件下盡可能的減少不必要的內(nèi)存開銷,從而達(dá)到節(jié)省內(nèi)存的效果,這么介紹有點(diǎn)玄乎,我們先一起看看它的實(shí)現(xiàn)原理吧,Redis3.2版本中,作者對壓縮列表的實(shí)現(xiàn)在ziplist.h和ziplist.c中。
壓縮列表原理
我認(rèn)為將數(shù)據(jù)按照一定規(guī)則存儲在內(nèi)存中可以用“編碼”這個(gè)詞描述,因此下面會常用“編碼”這個(gè)詞。
總體編碼
上面說到壓縮列表是一塊連續(xù)的內(nèi)存區(qū)域,這塊內(nèi)存區(qū)域布編碼示意圖大致如下:

Redis壓縮列表內(nèi)存編碼示意圖
常態(tài)的壓縮列表內(nèi)存編碼如上圖所示,整個(gè)內(nèi)存塊區(qū)域內(nèi)分為五個(gè)部分,下面分別介紹著五個(gè)部分:
zlbytes:存儲一個(gè)無符號整數(shù),固定四個(gè)字節(jié)長度,用于存儲壓縮列表所占用的字節(jié),當(dāng)重新分配內(nèi)存的時(shí)候使用,不需要遍歷整個(gè)列表來計(jì)算內(nèi)存大小。
zltail:存儲一個(gè)無符號整數(shù),固定四個(gè)字節(jié)長度,代表指向列表尾部的偏移量,偏移量是指壓縮列表的起始位置到指定列表節(jié)點(diǎn)的起始位置的距離。
zllen:壓縮列表包含的節(jié)點(diǎn)個(gè)數(shù),固定兩個(gè)字節(jié)長度,源碼中指出當(dāng)節(jié)點(diǎn)個(gè)數(shù)大于2^16-2個(gè)數(shù)的時(shí)候,該值將無效,此時(shí)需要遍歷列表來計(jì)算列表節(jié)點(diǎn)的個(gè)數(shù)。
entryX:列表節(jié)點(diǎn)區(qū)域,長度不定,由列表節(jié)點(diǎn)緊挨著組成。
zlend:一字節(jié)長度固定值為255,用于表示列表結(jié)束。
列表元素編碼
上面介紹了壓縮列表的總體內(nèi)存布局,對于初entryX區(qū)域以外的四個(gè)區(qū)域的長度都是固定的,下面再看看entryX區(qū)域的編碼情況。
每個(gè)列表節(jié)點(diǎn)由三部分組成:

壓縮列表節(jié)點(diǎn)編碼示意圖
每個(gè)壓縮列表節(jié)點(diǎn)區(qū)域頭部包含兩部分,一部分叫做previous length,另一部分叫encoding,最后是主體內(nèi)容,叫做content,下面分別介紹他們:
previous length
用于存儲上一個(gè)節(jié)點(diǎn)的長度,因此壓縮列表可以從尾部向頭部遍歷,即當(dāng)前節(jié)點(diǎn)位置減去上一個(gè)節(jié)點(diǎn)的長度即得到上一個(gè)節(jié)點(diǎn)的起始位置。previous length的長度可能是1個(gè)字節(jié)或者是5個(gè)字節(jié),如果上一個(gè)節(jié)點(diǎn)的長度小于254,則該節(jié)點(diǎn)只需要一個(gè)字節(jié)就可以表示前一個(gè)節(jié)點(diǎn)的長度了,如果前一個(gè)節(jié)點(diǎn)的長度大于等于254,則previous length的第一個(gè)字節(jié)為254,后面用四個(gè)字節(jié)表示當(dāng)前節(jié)點(diǎn)前一個(gè)節(jié)點(diǎn)的長度。這么做很有效地減少了內(nèi)存的浪費(fèi)。
encoding
節(jié)點(diǎn)的encoding保存的是節(jié)點(diǎn)的content的內(nèi)容類型以及長度,encoding類型一共有兩種,一種字節(jié)數(shù)組一種是整數(shù),encoding區(qū)域長度為1字節(jié)、2字節(jié)或者5字節(jié)長。Redis作者巧妙的利用了前兩個(gè)字節(jié)來表示content存儲的內(nèi)容類型和encoding區(qū)域的長度,我們先看看字節(jié)數(shù)組類型的encoding內(nèi)容:

content為字節(jié)數(shù)組的encoding內(nèi)容
再看看整數(shù)編碼類型的encoding內(nèi)容:

content為整數(shù)的encoding內(nèi)容
content
content區(qū)域用于保存節(jié)點(diǎn)的內(nèi)容,節(jié)點(diǎn)內(nèi)容類型和長度由encoding決定,上面可以看出目前content的內(nèi)容類型有整數(shù)類型和字節(jié)數(shù)組類型,且某些條件下content的長度可能為0。
相信到這里,我們都明白了壓縮列表的原理,壓縮列表并不是對數(shù)據(jù)利用某種算法進(jìn)行壓縮,而是將數(shù)據(jù)按照一定規(guī)則編碼在一塊連續(xù)的內(nèi)存區(qū)域,目的是節(jié)省內(nèi)存。下面我們看看壓縮列表在Redis中的應(yīng)用領(lǐng)域。
Redis中壓縮列表的應(yīng)用
Redis中,不同的數(shù)據(jù)類型廣泛地應(yīng)用了壓縮列表編碼,整理如下表:
Redis中數(shù)據(jù)結(jié)構(gòu)類型與壓縮列表的應(yīng)用
上表總結(jié)了壓縮列表編碼在Redis不同的數(shù)據(jù)類型中的應(yīng)用,Redis一共支持五種數(shù)據(jù)結(jié)構(gòu)類型,其中有三種數(shù)據(jù)結(jié)構(gòu)在一定條件下會應(yīng)用壓縮列表,至于什么條件后面會分析,值得一提的是Redis當(dāng)前支持的GEO(地理位置)對壓縮列表也有應(yīng)用,具體此處不做討論。
Redis壓縮列表應(yīng)用分析
上面部分介紹了Redis壓縮列表的原理與應(yīng)用,下面簡單分析一下,主要從通過試圖回答一些問題來分析:Redis為什么使用壓縮列表?使用壓縮列表的好處是什么?使用壓縮列表的好處還有什么?壓縮列表的應(yīng)用對與我們使用內(nèi)存有沒有什么啟發(fā)?
Redis對于每種數(shù)據(jù)結(jié)構(gòu)、無論是列表、哈希表還是有序集合,在決定是否應(yīng)用壓縮列表作為當(dāng)前數(shù)據(jù)結(jié)構(gòu)類型的底層編碼的時(shí)候都會依賴一個(gè)開關(guān)和一個(gè)閾值,開關(guān)用來決定我們是否要啟用壓縮列表編碼,閾值總的來說通常指當(dāng)前結(jié)構(gòu)存儲的key數(shù)量有沒有達(dá)到一個(gè)數(shù)值(條件),或者是value值長度有沒有達(dá)到一定的長度(條件)。任何策略都有其應(yīng)用場景,不同場景應(yīng)用不同策略。為什么當(dāng)前結(jié)構(gòu)存儲的數(shù)據(jù)條目達(dá)到一定數(shù)值使用壓縮列表就不好?壓縮列表的新增、刪除的操作平均時(shí)間復(fù)雜度為O(N),隨著N的增大,時(shí)間必然會增加,他不像哈希表可以以O(shè)(1)的時(shí)間復(fù)雜度找到存取位置,然而在一定N內(nèi)的時(shí)間復(fù)雜度我們可以容忍。然而壓縮列表利用巧妙的編碼技術(shù)除了存儲內(nèi)容盡可能的減少不必要的內(nèi)存開銷,將數(shù)據(jù)存儲于連續(xù)的內(nèi)存區(qū)域,這對于Redis本身來說是有意義的,因?yàn)镽edis是一款內(nèi)存數(shù)據(jù)庫軟件,想辦法盡可能減少內(nèi)存的開銷是Redis設(shè)計(jì)者一定要考慮的事情。
另外,經(jīng)過仔細(xì)琢磨,我認(rèn)為使用壓縮列表的好處除了節(jié)約內(nèi)存之外,還有減少內(nèi)存碎片的作用,我把這種行為叫做"合并存儲",也就是將很多小的數(shù)據(jù)塊存儲在一個(gè)比較大的內(nèi)存區(qū)域,試想想,如果我們將要存儲的數(shù)據(jù)都是很小的條目,我們?yōu)槊恳粋€(gè)數(shù)據(jù)條目都單獨(dú)的申請內(nèi)存,結(jié)果是這些條目將有可能分散在內(nèi)存的每一個(gè)角落,最終導(dǎo)致碎片增加,這是一件令人頭疼的事情。
總結(jié)
這篇文章在介紹Redis壓縮列表原理與應(yīng)用的基礎(chǔ)之上對Redis壓縮列表的應(yīng)用進(jìn)行分析,分析部分主要摻雜著個(gè)人的理解與認(rèn)知,如果有不同觀點(diǎn)或者補(bǔ)充觀點(diǎn),歡迎留言討論。
分享標(biāo)題:Redis壓縮列表原理與應(yīng)用分析
網(wǎng)站URL:http://www.chinadenli.net/article24/jdhije.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站制作、ChatGPT、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)