Redis 已是你們耳熟能詳的東西了,平常工做也都在使用,面試中也是高頻的會涉及到,那麼咱們對它究竟瞭解有多深入呢?node
我讀了幾本 Redis 相關的書籍,嘗試去了解它的具體實現,將一些底層的數據結構及實現原理記錄下來。面試
本文將介紹 Redis 中底層的 quicklist(快速列表) 的實現方法。 它是 Redis 中列表鍵的底層實現之一。redis
能夠看到圖中,這個鍵值爲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, 也就是普通鏈表來存儲數據有兩個弊端:數據結構
所以,定義了 quicklist, 將 linkedlist 和 ziplist 結合起來,造成一個,將多個 ziplist 經過先後指針互相鏈接起來的結構,能夠在必定程度上緩解上面說到的兩個問題。性能
爲了進一步節約內存,Reids 還能夠對 ziplist 進行壓縮存儲,應用 LZF 算法壓縮。學習
既然 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 深度歷險:核心原理和應用實踐》
完。
最後,歡迎關注個人我的公衆號【 呼延十 】,會不按期更新不少後端工程師的學習筆記。 也歡迎直接公衆號私信或者郵箱聯繫我,必定知無不言,言無不盡。
以上皆爲我的所思所得,若有錯誤歡迎評論區指正。
歡迎轉載,煩請署名並保留原文連接。
聯繫郵箱:huyanshi2580@gmail.com
更多學習筆記見我的博客或關注微信公衆號 < 呼延十 >------>呼延十