Redis中的壓縮列表

2022-04-08 08:43:13 字數 3176 閱讀 5532

??壓縮列表(ziplist)是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來做列表鍵的底層實現。

??例如,執行以下命令將建立乙個壓縮列表實現的列表鍵:

127.0.0.1:6379> rpush 1st 1 3 5 10086 "hello" "world"

(integer) 6

127.0.0.1:6379> object encoding 1st

"ziplist"

??列表鍵裡包含的都是1、3、5、10086這樣的小整數值,以及hello、world這樣的短字串。

??另外,當乙個雜湊鍵只包含少量鍵值對,並且每個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來作為雜湊鍵的底層實現。

??舉個例子,執行以下命令將建立乙個壓縮列表實現的雜湊鍵:

127.0.0.1:6379> hmset profile name jack age 28 job programmer

ok127.0.0.1:6379> object encoding profile

"ziplist"

??雜湊鍵裡面包含的所有鍵和值都是小整數值或者短字串。

??壓縮列表是redis為了節約記憶體而開發的,是由一系列特殊編碼的連續記憶體塊組成的順序型(sequential)資料結構。乙個壓縮列表可以包含任意多個節點(entry),每個節點可以儲存乙個位元組陣列或者乙個整數值。

??下圖展示了壓縮列表的各個組成部分:

??下表則記錄了各個組成部分的型別、長度以及用途:

??觀察下面給出的壓縮列表示例:

列表zlbytes屬性的值為0x50(十進位制80),表示壓縮列表的總長為80位元組。

列表zltail屬性的值為0x3c(十進位制60),這表示如果我們有乙個指向壓縮列表起始位址的指標p,那麼只要用指標p加上偏移量60,就可以計算出表尾節點entry3的位址。

列表zllen屬性的值為0x3(十進位制3),表示壓縮列表包含三個節點。

??再觀察另乙個壓縮列表示例:

列表zlbytes屬性的值為0xd2(十進位制210),表示壓縮列表的總長為210位元組。

列表zltail屬性的值為0xb3(十進位制179),這表示如果我們有乙個指向壓縮列表起始位址的指標p,那麼只要用指標p加上偏移量179,就可以計算出表尾節點entry5的位址。

列表zllen屬性的值為0x5(十進位制5),表示壓縮列表包含五個節點。

??每個壓縮列表節點可以儲存乙個位元組陣列或者乙個整數值,其中,位元組陣列可以是以下長度的其中一種:

長度小於等於63(2^6 - 1)位元組的位元組陣列;

長度小於等於16383(2^14 - 1)位元組的位元組陣列;

長度小於等於4294967295(2^32 - 1)位元組的位元組陣列;

??而整數值則可以是以下六種長度的其中一種:

4位長,介於0至12之間的無符號整數;

1位元組長的有符號;

3位元組長的有符號整數;

int16_t型別整數;

int32_t型別整數;

int64_t型別整數。

??每個壓縮列表節點都由previous_entry_length、encoding、content三個部分組成:

previous_entry_length

??節點的previous_entry_length屬性以位元組為單位,記錄了壓縮列表中前乙個節點的長度。previous_entry_length屬性的長度可以是1位元組或者5位元組:

如果前一節點的長度小於254位元組,那麼previous_entry_length屬性的長度為1位元組:前一節點的長度就儲存在這乙個位元組裡面。

如果前一節點的長度大於等於254位元組,那麼previous_entry_length屬性的長度為5位元組:其中屬性的第一位元組會被設定為0xfe(十進位制254),而之後的四個位元組則用於儲存前一節點的長度。

??下圖展示了乙個包含一位元組長previous_entry_length屬性的壓縮列表節點,屬性值為0x05,表示前一節點的長度為5位元組。

??下圖展示了乙個包含五位元組長previous_entry_length屬性的壓縮節點,屬性的值為0xfe00002766,其中值的最高位位元組0xfe表示這是乙個五位元組長的previous_entry_length屬性,而之後的四位元組0x00002766(十進位制10086)才是前一位元組的實際長度。

??因為節點的previous_entry_length屬性記錄了前乙個節點的長度,所以程式可以通過指標運算,根據當前節點的起始位址來計算出前一節點的起始位址。

??舉個例子,如果我們有乙個指向當前節點起始位址的指標c,那麼我們只要用指標c減去當前節點previous_entry_length屬性的值,就可以得出乙個指向前乙個節點起始位址的指標p,如下圖所示:

??壓縮列表的從表尾向表頭遍歷操作就是使用這一原理實現的,只要我們擁有乙個指向某個節點起始位址的指標,那麼通過這個指標以及這個節點的previous_entry_length屬性,程式就可以一直向前乙個節點回溯,最終到達壓縮列表的表頭節點。

encoding

??節點的encoding屬性記錄了節點的content屬性所儲存資料的型別以及長度:

一位元組、兩位元組或者五位元組長,值的最高位為00、01或者10的是位元組陣列編碼:這種編碼表示節點的content屬性儲存著位元組陣列,陣列的長度由編碼除去最高兩位之後的其他位記錄;

一位元組長,值的最高位以11開頭的是整數編碼:這種編碼表示節點的content屬性儲存著整數值,整數值的型別和長度由編碼除去最高兩位之後的其他位記錄;

??下表記錄了所有可用的位元組陣列編碼,**中的下劃線表示留空,而b、x等變數則代表實際的二進位制資料,為了方便閱讀,多個位元組之間用空格隔開:

??下表記錄了所有可用的整數編碼:

content

??節點的content屬性負責儲存節點的值,節點值可以是乙個位元組陣列或者整數,值的型別和長度由節點的encoding屬性決定。

??下圖展示了乙個儲存位元組陣列的節點示例:

編碼的最高兩位00表示節點儲存的是乙個位元組陣列;

編碼的後六位001011記錄了位元組陣列的長度為11;

content屬性儲存著節點的值:hello world。

??下圖展示了乙個儲存著整數值的節點示例:

編碼11000000表示節點儲存的是乙個int16_t型別的整數值;

content屬性儲存著節點的值10086。

Redis中的壓縮列表

壓縮列表 ziplist 是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來做列表鍵的底層實現。例如,執行以下命令將建立乙個壓縮列表實現的列表鍵 127.0 0.1 6379 rpush 1st 1...

redis 壓縮列表

壓縮列表是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會使用壓縮列表來做列表鍵的底層實現。另外,當乙個雜湊鍵只包含少量鍵值對,並且每個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字串,那麼redis就會...

Redis之壓縮列表

壓縮列表 ziplist 是列表鍵和雜湊鍵的底層實現之一。當乙個列表鍵只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,redis就會使用壓縮列表來做列表鍵的底層實現。下面看一下壓縮列表實現的列表鍵 列表鍵裡面包含的都是1 3 5 10086這樣的小整數值,以及 hello...