Redis之壓縮列表
同整數集合一樣壓縮列表也不是基礎資料結構,而是 Redis 自己設計的一種資料儲存結構。它有點兒類似陣列,通過一片連續的記憶體空間,來儲存資料。不過,它跟陣列不同的一點是,它允許儲存的資料大小不同。
壓縮列表
聽到“壓縮”兩個字,直觀的反應就是節省記憶體。之所以說這種儲存結構節省記憶體,是相較於陣列的儲存思路而言的。我們知道,陣列要求每個元素的大小相同,如果我們要儲存不同長度的字串,那我們就需要用最大長度的字串大小作為元素的大小(假設是20個位元組)。儲存小於 20 個位元組長度的字串的時候,便會浪費部分儲存空間。
陣列的優勢佔用一片連續的空間可以很好的利用CPU快取訪問資料。如果我們想要保留這種優勢,又想節省儲存空間我們可以對陣列進行壓縮。
但是這樣有一個問題,我們在遍歷它的時候由於不知道每個元素的大小是多少,因此也就無法計算出下一個節點的具體位置。這個時候我們可以給每個節點增加一個lenght的屬性。
如此。我們在遍歷節點的之後就知道每個節點的長度(佔用記憶體的大小),就可以很容易計算出下一個節點再記憶體中的位置。這種結構就像一個簡單的壓縮列表了。
Redis壓縮列表
壓縮列表(zip1ist)是列表和雜湊的底層實現之一。 當一個列表只包含少量列表項,並且每個列表項要麼就是小整數值,要麼就是長度比較短的字串,那麼Redis就會使用壓縮列表來做列表的底層實現。 當一個雜湊只包含少量鍵值對,比且每個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字串,那麼Redis就會使用壓縮列表來做雜湊的底層實現。
實現
壓縮列表是Redis為了節約記憶體而開發的,是由一系列特殊編碼的連續記憶體塊組成的順序型(sequential)資料結枃。一個壓縮列表可以包含任意多個節點(entry),每個節點可以儲存一個位元組陣列或者一個整數值,如下圖。
壓縮列表節點構成
每個壓縮列表節點可以儲存一個位元組陣列或者一個整數值。其中,位元組陣列可以是以下三種長度中的一種。
-
長度小於等於63(2^6-1)位元組的位元組陣列;
-
長度小於等於16383(2^14-1)位元組的位元組陣列
-
長度小於等於4294967295(2^32-1)位元組的位元組陣列
整數值可以是以下6種長度中的一種
-
4位長,介於0至12之間的無符號整數
-
1位元組長的有符號整數
-
3位元組長的有符號整數
-
int16_t型別整數
-
int32_t型別整數
-
int64_t型別整數
節點的 previous_entry_length屬性以位元組為單位,記錄了壓縮列表中前一個節點的長度。 previous_entry_length屬性的長度可以是1位元組或者5位元組。
-
如果前一節點的長度小於254位元組,那麼 previous_entry_length屬性的長度為1位元組,前一節點的長度就儲存在這一個位元組裡面。
-
如果前一節點的長度大於等於254位元組,那麼 previous_entry_length屬性的長度為5位元組:其中屬性的第一位元組會被設定為0xFE(十進位制值254),而之後的四個位元組則用於儲存前一節點的長度.
節點的encoding屬性記錄了節點的content屬性所儲存資料的型別以及長度。
- 一位元組、兩位元組或者五位元組長,值的最高位為00、01或者10的是位元組陣列編碼這種編碼表示節點的 content屬性儲存著位元組陣列,陣列的長度由編碼除去最高兩位之後的其他位記錄。
- 一位元組長,值的最高位以11開頭的是整數編碼:這種編碼表示節點的content屬性儲存著整數值,整數值的型別和長度由編碼除去最高兩位之後的其他位記錄。
節點的content屬性負責儲存節點的值,節點值可以是一個位元組陣列或者整數,值的型別和長度由節點的encoding屬性決定。
我有一壺酒 足以慰風塵 盡傾江海里 贈飲天下人