Redis壓縮列表原理與應用分析

摘要

Redis是一款著名的key-value內存數據庫軟件,同時也是一款卓越的數據結構服務軟件。它支持字符串、列表、哈希表、集合、有序集合五種數據結構類型,同時每種數據結構類型針對不一樣的應用場景又支持不一樣的編碼方式。這篇文章主要介紹壓縮列表編碼,在理解壓縮列表編碼原理的基礎上介紹Redis對壓縮列表的應用,最後再對Redis壓縮列表應用進行分析。算法

Redis壓縮列表原理與應用

壓縮列表是一種數據結構,這種數據結構的功能是將一系列數據與其編碼信息存儲在一塊連續的內存區域,這塊內存物理上是連續的,邏輯上被分爲多個組成部分,其目的是在必定可控的時間複雜讀條件下儘量的減小沒必要要的內存開銷,從而達到節省內存的效果,這麼介紹有點玄乎,咱們先一塊兒看看它的實現原理吧,Redis3.2版本中,做者對壓縮列表的實如今ziplist.h和ziplist.c中。數據庫

壓縮列表原理    

我認爲將數據按照必定規則存儲在內存中能夠用「編碼」這個詞描述,所以下面會經常使用「編碼」這個詞。數組

整體編碼

上面說到壓縮列表是一塊連續的內存區域,這塊內存區域布編碼示意圖大體以下:數據結構

Redis壓縮列表內存編碼示意圖佈局

常態的壓縮列表內存編碼如上圖所示,整個內存塊區域內分爲五個部分,下面分別介紹着五個部分:編碼

zlbytes:存儲一個無符號整數,固定四個字節長度,用於存儲壓縮列表所佔用的字節,當從新分配內存的時候使用,不須要遍歷整個列表來計算內存大小。spa

zltail:存儲一個無符號整數,固定四個字節長度,表明指向列表尾部的偏移量,偏移量是指壓縮列表的起始位置到指定列表節點的起始位置的距離。設計

zllen:壓縮列表包含的節點個數,固定兩個字節長度,源碼中指出當節點個數大於2^16-2個數的時候,該值將無效,此時須要遍歷列表來計算列表節點的個數。ip

entryX:列表節點區域,長度不定,由列表節點緊挨着組成。內存

zlend:一字節長度固定值爲255,用於表示列表結束。

列表元素編碼

上面介紹了壓縮列表的整體內存佈局,對於初entryX區域之外的四個區域的長度都是固定的,下面再看看entryX區域的編碼狀況。

每一個列表節點由三部分組成:

壓縮列表節點編碼示意圖

每一個壓縮列表節點區域頭部包含兩部分,一部分叫作previous length,另外一部分叫encoding,最後是主體內容,叫作content,下面分別介紹他們:

previous length

用於存儲上一個節點的長度,所以壓縮列表能夠從尾部向頭部遍歷,即當前節點位置減去上一個節點的長度即獲得上一個節點的起始位置。previous length的長度多是1個字節或者是5個字節,若是上一個節點的長度小於254,則該節點只須要一個字節就能夠表示前一個節點的長度了,若是前一個節點的長度大於等於254,則previous length的第一個字節爲254,後面用四個字節表示當前節點前一個節點的長度。這麼作頗有效地減小了內存的浪費。

encoding

節點的encoding保存的是節點的content的內容類型以及長度,encoding類型一共有兩種,一種字節數組一種是整數,encoding區域長度爲1字節、2字節或者5字節長。Redis做者巧妙的利用了前兩個字節來表示content存儲的內容類型和encoding區域的長度,咱們先看看字節數組類型的encoding內容:

content爲字節數組的encoding內容

再看看整數編碼類型的encoding內容:

content爲整數的encoding內容

content

content區域用於保存節點的內容,節點內容類型和長度由encoding決定,上面能夠看出目前content的內容類型有整數類型和字節數組類型,且某些條件下content的長度可能爲0。

相信到這裏,咱們都明白了壓縮列表的原理壓縮列表並非對數據利用某種算法進行壓縮,而是將數據按照必定規則編碼在一塊連續的內存區域,目的是節省內存。下面咱們看看壓縮列表在Redis中的應用領域。

Redis中壓縮列表的應用

Redis中,不一樣的數據類型普遍地應用了壓縮列表編碼,整理以下表:

Redis中數據結構類型與壓縮列表的應用

上表總結了壓縮列表編碼在Redis不一樣的數據類型中的應用,Redis一共支持五種數據結構類型,其中有三種數據結構在必定條件下會應用壓縮列表,至於什麼條件後面會分析,值得一提的是Redis當前支持的GEO(地理位置)對壓縮列表也有應用,具體此處不作討論。

Redis壓縮列表應用分析

上面部分介紹了Redis壓縮列表的原理與應用,下面簡單分析一下,主要從經過試圖回答一些問題來分析:Redis爲何使用壓縮列表?使用壓縮列表的好處是什麼?使用壓縮列表的好處還有什麼?壓縮列表的應用對與咱們使用內存有沒有什麼啓發?

Redis對於每種數據結構、不管是列表、哈希表仍是有序集合,在決定是否應用壓縮列表做爲當前數據結構類型的底層編碼的時候都會依賴一個開關和一個閾值,開關用來決定咱們是否要啓用壓縮列表編碼,閾值總的來講一般指當前結構存儲的key數量有沒有達到一個數值(條件),或者是value值長度有沒有達到必定的長度(條件)。任何策略都有其應用場景,不一樣場景應用不一樣策略。爲何當前結構存儲的數據條目達到必定數值使用壓縮列表就很差?壓縮列表的新增、刪除的操做平均時間複雜度爲O(N),隨着N的增大,時間必然會增長,他不像哈希表能夠以O(1)的時間複雜度找到存取位置,然而在必定N內的時間複雜度咱們能夠容忍然而壓縮列表利用巧妙的編碼技術除了存儲內容儘量的減小沒必要要的內存開銷,將數據存儲於連續的內存區域,這對於Redis自己來講是有意義的,由於Redis是一款內存數據庫軟件,想辦法儘量減小內存的開銷是Redis設計者必定要考慮的事情。

另外,通過仔細琢磨,我認爲使用壓縮列表的好處除了節約內存以外,還有減小內存碎片的做用,我把這種行爲叫作"合併存儲",也就是將不少小的數據塊存儲在一個比較大的內存區域,試想一想,若是咱們將要存儲的數據都是很小的條目,咱們爲每個數據條目都單獨的申請內存,結果是這些條目將有可能分散在內存的每個角落,最終致使碎片增長,這是一件使人頭疼的事情。

總結

這篇文章在介紹Redis壓縮列表原理與應用的基礎之上對Redis壓縮列表的應用進行分析,分析部分主要摻雜着我的的理解與認知,若是有不一樣觀點或者補充觀點,歡迎留言討論。

相關文章
相關標籤/搜索