圖解Redis之數據結構篇——壓縮列表

文章導航-readme

前言

    同整數集合同樣壓縮列表也不是基礎數據結構,而是 Redis 本身設計的一種數據存儲結構。它有點兒相似數組,經過一片連續的內存空間,來存儲數據。不過,它跟數組不一樣的一點是,它容許存儲的數據大小不一樣。html

1、壓縮列表

    聽到「壓縮」兩個字,直觀的反應就是節省內存。之因此說這種存儲結構節省內存,是相較於數組的存儲思路而言的。咱們知道,數組要求每一個元素的大小相同,若是咱們要存儲不一樣長度的字符串,那咱們就須要用最大長度的字符串大小做爲元素的大小(假設是20個字節)。存儲小於 20 個字節長度的字符串的時候,便會浪費部分存儲空間。redis

    數組的優點佔用一片連續的空間能夠很好的利用CPU緩存訪問數據。若是咱們想要保留這種優點,又想節省存儲空間咱們能夠對數組進行壓縮。數組

     可是這樣有一個問題,咱們在遍歷它的時候因爲不知道每一個元素的大小是多少,所以也就沒法計算出下一個節點的具體位置。這個時候咱們能夠給每一個節點增長一個lenght的屬性。緩存

    如此。咱們在遍歷節點的以後就知道每一個節點的長度(佔用內存的大小),就能夠很容易計算出下一個節點再內存中的位置。這種結構就像一個簡單的壓縮列表了。數據結構

2、Redis壓縮列表

    壓縮列表(zip1ist)是列表和哈希的底層實現之一。運維

    當一個列表只包含少許列表項,而且每一個列表項要麼就是小整數值,要麼就是長度比較短的字符串,那麼Redis就會使用壓縮列表來作列表的底層實現。編碼

    當一個哈希只包含少許鍵值對,比且每一個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字符串,那麼Redis就會使用壓縮列表來作哈希的底層實現。設計

2.1 Redis壓縮列表的構成

    壓縮列表是Redis爲了節約內存而開發的,是由一系列特殊編碼的連續內存塊組成的順序型(sequential)數據結枃。一個壓縮列表能夠包含任意多個節點(entry),每一個節點能夠保存一個字節數組或者一個整數值,以下圖。指針

示例:htm

    如上圖,展現了一個總長爲80字節,包含3個節點的壓縮列表。若是咱們有一個指向壓縮列表起始地址的指針p,那麼表爲節點的地址就是P+60。

2.2 Redis壓縮列表節點的構成

    每一個壓縮列表節點能夠保存一個字節數組或者一個整數值。其中,字節數組能夠是如下三種長度中的一種。

  • 長度小於等於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屬性決定。

  • 編碼的最高兩位00表示節點保存的是一個字節數組。
  • 編碼的後六位001011記錄了字節數組的長度11。
  • content屬性保存着節點的值"hello world"。
  • 編碼11000000表示節點保存的是一個int16_t類型的整數值;
  • content屬性保存着節點的值10086

2.3 經常使用操做的時間複雜度

操做 時間複雜度
建立一個新的壓縮列表 O(1)
建立一個包含給定值的新節點,並將這個新節點添加到壓縮列表的表頭或者表尾 平均O(N),最壞O(N^2)(可能發生連鎖更新)
將包含給定值的新節點插人到給定節點以後 平均O(N),最壞O(N^2)(可能發生連鎖更新)
返回壓縮列表給定索引上的節點 O(N)
在壓縮列表中査找並返回包含了給定值的節點 由於節點的值多是一個字節數組,因此檢查節點值和給定值是否相同的複雜度爲O(N),而查找整個列表的複雜度則爲(N^2)
返回給定節點的下一個節點 O(1)
返回給定節點的前一個節點 O(1)
獲取給定節點所保存的值 O(1)
從壓縮列表中刪除給定的節點 平均O(N),最壞O(N^2)(可能發生連鎖更新)
刪除壓縮列表在給定索引上的連續多個 平均O(N),最壞O(N^2)(可能發生連鎖更新)
返回壓縮列表目前佔用的內存字節數 O(1)
返回壓縮列表目前包含的節點數量 點數量小於65535時爲O(1),大於65535時爲O(N)

本文重點

  • 壓縮列表是Redis爲節約內存本身設計的一種順序型數據結構。

  • 壓縮列表被用做列表鍵和哈希鍵的底層實現之一。
  • 壓縮列表能夠包含多個節點,每一個節點能夠保存一個字節數組或者整數值。
  • 添加新節點到壓縮列表,或者從壓縮列表中刪除節點,可能會引起連鎖更新操做,但這種操做出現的概率並不高。

參考

《Redis設計與實現》

《Redis開發與運維》

《Redis官方文檔》

-----END-----

相關文章
相關標籤/搜索