5分鍾了解Redis的內部實現快速列表(quicklist)


快速列表簡介

在Redis3 .2版本之前,存儲列表(list)數據結構使用的是壓縮列表(ziplist)和鏈表(linkedlist),當列表元素個數比較少並且每個元素占用空間比較小的時候,使用壓縮列表。當列表元素個數比較多或者某個元素占用空間比較大的時候,使用鏈表。

考慮到鏈表的附加空間相對太高,結點的內存也是單獨分配的,影響內存管理效率。在Redis3 .2版本開始對列表數據結構進行了改造,使用快速列表(quicklist)代替了壓縮列表(ziplist)和鏈表(linkedlist)。

快速列表(quicklist)是以壓縮列表(ziplist)為節點的鏈表(linkedlist),將鏈表按段切分,每一段使用壓縮列表進行內存的連續存儲,多個壓縮列表通過prev和next指針組成的雙向鏈表。它結合了壓縮列表和鏈表的優勢,進一步壓縮了內存的使用量,進一步提高了效率。

下面我們了解一下快速列表的具體實現。

快速列表的實現

在Redis中的快速列表是由quicklist結構表示的,quicklist結構包含由多個快速列表結點組成的雙向鏈表,每一個快速列表結點都保存了一個壓縮列表。下面我們一個一個地詳細了解一下。

quicklist結構

快速列表是由quicklist結構表示的,它包含以下幾個屬性:

  • head屬性: 指向頭部快速列表結點的指針。
  • tail屬性:指向尾部快速列表結點的指針。
  • count屬性:在所有壓縮列表中元素的個數總和。
  • len屬性:快速列表結點的個數。
  • fill屬性:壓縮列表的最大大小,存放list-max-ziplist-size參數的值。當超出了這個配置,就會新建一個壓縮列表。
  • compress屬性:結點壓縮深度,存放list-compress-depth參數的值。
  • bookmarks屬性:用來快速列表重新分配內存空間時使用的數組,不使用時不占用空間。
  • bookmark_count屬性:bookmarks數組的大小。

快速列表結點

快速列表結點使用quicklistNode結構表示,它包含以下幾個屬性:

  • prev屬性:指向前一個快速列表結點的指針。
  • next屬性:指向后一個快速列表結點的指針。
  • zl屬性:指向壓縮列表的指針,如果當前結點的數據被壓縮,那么它指向一個quicklistLZF結構。
  • sz屬性:壓縮列表的所占字節總數。
  • count屬性:壓縮列表中的元素數量。
  • encoding屬性:存儲形式,原生字節數組還是LZF壓縮存儲。
  • recompress屬性:當查看了某一項被壓縮的數據時,需要把數據暫時解壓,這時就設置 recompress = 1 做一個標記,等有機會再把數據重新壓縮。

quicklistLZF結構

當快速列表結點數據被壓縮時,數據會被存放在quicklistLZF結構中,它包含以下幾個屬性:

  • sz屬性:表示壓縮后的大小。
  • compressed屬性:存放壓縮后的字節數組。

快速列表的壓縮機制

在快速列表中,兩端結點的數據被訪問的可能性比較高,中間結點的數據被訪問的可能性比較低。如果我們的應用場景符合這個特點,可以把中間結點的數據使用 LZF 算法進行壓縮,從而進一步節省內存空間。我們可以對list-compress-depth參數進行配置。

默認情況下,list-compress-depth參數為0,也就是不壓縮數據;當該參數被設置為1時,除了頭部和尾部之外的結點都會被壓縮;當該參數被設置為2時,除了頭部、頭部的下一個、尾部、尾部的上一個之外的結點都會被壓縮;當該參數被設置為2時,除了頭部、頭部的下一個、頭部的下一個的下一個、尾部、尾部的上一個、尾部的上一個的上一個之外的結點都會被壓縮;以此類推。

最后,謝謝你這么帥,還給我點贊關注

微信公眾號:萬貓學社

微信掃描二維碼

關注后回復「電子書」

獲取12本Java必讀技術書籍


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM