Redis系列(四)底層數據結構之快速列表

前言

Redis 已是你們耳熟能詳的東西了,平常工做也都在使用,面試中也是高頻的會涉及到,那麼咱們對它究竟瞭解有多深入呢?node

我讀了幾本 Redis 相關的書籍,嘗試去了解它的具體實現,將一些底層的數據結構及實現原理記錄下來。面試

本文將介紹 Redis 中底層的 quicklist(快速列表) 的實現方法。 它是 Redis 中列表鍵的底層實現之一。redis

2020-01-05-16-56-43

能夠看到圖中,這個鍵值爲listkey的 list 內部使用的編碼方法就是 quicklist.算法

定義

quicklist 是 ziplist 和 linkedlist 的一個結合體。它的結構定義以下:後端

struct ziplist_compressed{
    int32 size;
    byte[]  compressed_data;
}

struct quicklistNode {
    quicklistNode* prev;
    quicklistNode* next;
    // 指向壓縮列表
    ziplist* zi; 
    // ziplist 的字節總數
    int32 size;
    // ziplist 的元素總數
    int 16 count;
    // 存儲形式,是原生的字節數組,仍是 LZF 壓縮存儲
    int2 encoding;
}

struct quicklist{
    // 頭結點
    quicklistNode* head;
    // 尾節點
    quicklistNode* tail;
    // 元素總數
    long count;
    // ziplist 節點的個數
    int nodes;
    // LZF 算法壓縮深度
    int compressDepth;
}
複製代碼

從結構定義中能夠看到,quicklist 的定義和 鏈表的很像,本質上也是一個雙端的鏈表,只是把普通的節點換成了 quicklistNode, 在這個節點中,保存的不是一個簡單的值,而是一個 ziplist.數組

優劣

爲何要定義一個 quicklist, 列表結構還不夠多嗎???微信

純粹的使用 Linkedlist, 也就是普通鏈表來存儲數據有兩個弊端:數據結構

  1. 每一個節點都有本身的先後指針,指針所佔用的內存有點多,太浪費了。
  2. 每一個節點單獨的進行內存分配,當節點過多,形成的內存碎片太多了。影響內存管理的效率。

所以,定義了 quicklist, 將 linkedlist 和 ziplist 結合起來,造成一個,將多個 ziplist 經過先後指針互相鏈接起來的結構,能夠在必定程度上緩解上面說到的兩個問題。性能

爲了進一步節約內存,Reids 還能夠對 ziplist 進行壓縮存儲,應用 LZF 算法壓縮。學習

ziplist 切割大小

既然 quicklist 本質上是將 ziplist 鏈接起來,那麼每一個 ziplist 存放多少的元素,就成爲了一個問題。

過小的話起不到應有的做用,極致小的話(爲 1 個元素), 快速列表就退化成了普通的鏈表。

太大的話性能太差,極致大的話(整個快速列表只用一個 ziplist), 快速列表就退化成了 ziplist.

quickli 內部默認定義的單個 ziplist 的大小爲 8k 字節. 超過這個大小,就會從新分配一個 ziplist 了。這個長度能夠由參數list-max-ziplist-size來控制。

壓縮深度

前面提到了,quicklist 能夠對 ziplist 來進行壓縮,並且能夠指定壓縮深度。(由list-compress-depth參數決定).

默認的壓縮深度爲 0, 也就是全部的節點都不壓縮。

爲了支持快速的 push/pop 操做,quicklist 兩端的第一個 ziplist 不進行壓縮,這時壓縮深度爲 1.

若是壓縮深度爲 2, 則是兩端各自兩個 ziplist 不壓縮。

由於若是將一個 ziplist 壓縮,那麼要從它裏面讀取值,必然要先解壓,會形成性能變差,所以能夠將兩端即將被操做的節點不壓縮,其餘的選擇壓縮。

總結

總結,爲了解決 linkedlist 的雙向指針佔用內存過多,以及 ziplist 數據量太大性能就變差的問題,結合他們兩個產出了新的數據結構,也就是 quicklist.

它將多個 ziplist 經過先後節點的指針鏈接起來,在必定程度上解決了上面的問題,提升了 Redis 的響應速度。

參考文章

《Redis 的設計與實現(第二版)》

《Redis 深度歷險:核心原理和應用實踐》

matt.sh/redis-quick…


完。

聯繫我

最後,歡迎關注個人我的公衆號【 呼延十 】,會不按期更新不少後端工程師的學習筆記。 也歡迎直接公衆號私信或者郵箱聯繫我,必定知無不言,言無不盡。


以上皆爲我的所思所得,若有錯誤歡迎評論區指正。

歡迎轉載,煩請署名並保留原文連接。

聯繫郵箱:huyanshi2580@gmail.com

更多學習筆記見我的博客或關注微信公衆號 < 呼延十 >------>呼延十

相關文章
相關標籤/搜索