Redis系列(八)底層數據結構之緊湊列表

前言

Redis 已經是大家耳熟能詳的東西了,日常工作也都在使用,面試中也是高頻的會涉及到,那麼我們對它究竟瞭解有多深刻呢?

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

本文將介紹 Redis 中底層的 listpack(緊湊列表) 的實現方法。 它是 Redis 的 Stream 用到的數據結構之一。

定義

Redis 設計 listpack 的目的就是取代 ziplist, 在 Redis 系列(三)底層數據結構之壓縮列表 中我們提到,ziplist 在極小的概率下有可能發生級聯更新,當連續規模較大的級聯更新發生時,對 Redis 的性能有比較大的影響。

雖然我們都知道這是極小的概率,但是這種設計缺陷卻不能被 Redis 的大佬作者所接受,因此在 5.0 版本中新引入了一個數據結構,名叫 listpack, 大家都將它翻譯爲 緊湊列表.

它的定義和 ziplist 極其相似,只是通過一些新的設計,來解決 ziplist 中的痛點問題。因此本文的講解基於讀者已經瞭解 ziplist.

ziplist的定義如下:
注意:這是 ziplist 的定義

struct ziplist<T>{
    // 整個壓縮列表佔用字節數
    int32 zlbytes;
    // 最後一個節點到壓縮列表起始位置的偏移量,可以用來快速的定位到壓縮列表中的最後一個元素
    int32 zltail_offset;
    // 壓縮列表包含的元素個數
    int16 zllength;
    // 元素內容列表,用數組存儲,內存上緊挨着
    T[] entries;
    // 壓縮列表的結束標誌位,值永遠爲 0xFF.
    int8 zlend;
}

listpack 的定義和上方基本一致,只是去掉了 zltail_offset 屬性。

讓我們回想一下,ziplist 中用這個屬性做什麼?用來方便的找到最後一個節點,然後方便進行反向的遍歷。新的 listpack 當然是解決了這個問題,才能放心的刪除掉這個屬性。

listpack節點的定義如下:

int<var> encoding;
optional byte[] content;
int<var> length;

相比於 ziplist 的定義,它有兩點改動:

  1. 記錄的長度不再是前一個節點的長度,而是自己的長度。
  2. 將記錄自己的長度放到了節點的尾部。

這樣做的好處是:

  1. 不再需要 zltail_offset 屬性也可以快速定位到最後一個節點。用listpac 的總長度-最後一個節點的長度.
  2. 每個節點記錄自己的長度,當本節點的值發生了改變,只需要更改自己的長度即可。不再需要更改別的節點的屬性,也就徹底的解決掉了級聯更新問題。

總結

listpack 是 Redis 設計用來取代掉 ziplist 的數據結構,它通過每個節點記錄自己的長度,且放在節點的尾部,來徹底解決掉了 ziplist 存在的級聯更新的問題。

listpack 在 5.0 版本引入,但是由於 ziplist 在 Reids 內部的使用太過於廣泛,有一些兼容問題,我們可以預見這將是一個逐步的替換過程。

同樣在 5.0 版本引入的 Stream 數據結構中,就使用了 listpack 而不是 ziplist.

參考文章

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

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

完。

聯繫我

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


以上皆爲個人所思所得,如有錯誤歡迎評論區指正。

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

聯繫郵箱:[email protected]

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章