你確定不來了解一下Redis列表的原理嗎

前言

在上一章中我們介紹了 String 的一些內(nèi)部原理,在這一章中我們再來討論在五種數(shù)據(jù)結(jié)構(gòu)中 List 的基本使用和一些內(nèi)部實(shí)現(xiàn).

基本介紹

Redis的List 呢相當(dāng)于 Java 中的 LinkedList,也是雙向鏈表.具有一些和 LinkedList 同樣的特征,比如插入和刪除一條很快,時(shí)間復(fù)雜度為 O(1),獲取頭結(jié)點(diǎn)和尾節(jié)點(diǎn)也很快,時(shí)間復(fù)雜度也為 O(1),隨機(jī)讀取則相對較慢時(shí)間復(fù)雜度為 O(n).常用作消息隊(duì)列.

當(dāng)做隊(duì)列使用時(shí),遵循先進(jìn)先出原則:

> rpush books python java golang
(integer) 3
> lpop books
"python"
> lpop books
"java"

當(dāng)做棧使用時(shí),遵循先進(jìn)后出原則:

> rpush books python java golang
(integer) 3
> rpop books
"golang"
> rpop books
"java"

同時(shí)還可以通過 get(index)的方法獲取:

> rpush books python java golang
(integer) 3
> lindex books 0
"python"
> lindex books -1
"golang"

index從 0 開始,可以為負(fù)數(shù) -1 代表倒數(shù)第一個(gè)元素

內(nèi)部實(shí)現(xiàn)

上述部分我們把 Redis 中的 List當(dāng)做 Java 中的 LinkedList 操作,因?yàn)橛泻芏嘞嗤牟糠?但實(shí)際上在 Redis 中鏈表的內(nèi)部實(shí)現(xiàn)可不是一個(gè)簡單的雙向鏈表.在數(shù)據(jù)量較少的時(shí)候它的底層存儲結(jié)構(gòu)為一塊連續(xù)內(nèi)存,稱之為ziplist(壓縮列表).當(dāng)數(shù)據(jù)量較多的時(shí)候?qū)兂涉湵淼慕Y(jié)構(gòu).后來因?yàn)殒湵硇枰?prev 和 next 兩個(gè)指針占用內(nèi)存很多,改用 ziplist+鏈表的混合結(jié)構(gòu),稱之為 quicklist(快速鏈表).在新的版本中 Redis 鏈表統(tǒng)一使用 quicklist來存儲.下面我們就來詳細(xì)介紹這種數(shù)據(jù)結(jié)構(gòu).

ziplist 壓縮列表

先來看看 ziplist 的數(shù)據(jù)結(jié)構(gòu):

struct ziplist<T>{
    int32 zlbytes;          //壓縮列表占用字節(jié)數(shù)
    int32 zltail_offset;    //最后一個(gè)元素距離起始位置的偏移量,用于快速定位到最后一個(gè)節(jié)點(diǎn)
    int16 zllength;         //元素個(gè)數(shù)
    T[] entries;            //元素內(nèi)容
    int8 zlend;             //結(jié)束位 0xFF
}

如圖所示:

image

有了 ztail_offset 就可以快速的定位到最后一個(gè)節(jié)點(diǎn),這樣就可以倒序遍歷了.也就是說 ziplist支持雙向遍歷.

下面再來看下 entry 的內(nèi)部實(shí)現(xiàn):

struct entry{
    int<var> prevlen;           //前一個(gè) entry 的長度
    int<var> encoding;          //元素類型編碼
    optional byte[] content;    //元素內(nèi)容
}

當(dāng) ziplist 倒序遍歷的時(shí)候,就是通過這個(gè)pervlen定位到前一個(gè)元素位置的.
encoding 保存了 content 的編碼類型.
content 則是保存的元素內(nèi)容,它是optional 類型表示是這個(gè)字段是可選的.當(dāng)content 是很小的整數(shù)時(shí),他會內(nèi)聯(lián)到 encoding 字段的尾部.

quicklist 快速列表

quicklist 是 ziplist 和鏈表的混合體.下面是 quicklist和 node 的部分?jǐn)?shù)據(jù)結(jié)構(gòu):

struct quicklist{
    quicklistNode* head;    //指向頭結(jié)點(diǎn)
    quicklistNode* tail;    //指向尾節(jié)點(diǎn)
    long count;             //元素總數(shù)
    int nodes;              //quicklistNode節(jié)點(diǎn)的個(gè)數(shù)
    int compressDepth;      //壓縮算法深度
    ...
}

為了節(jié)約空間 Redis 還會對 ziplist 使用 LZF 算法進(jìn)行壓縮,可以選擇壓縮深度.我們待會在說.

image

如上圖所示,quicklist含有兩個(gè) quicklistNode 代表頭結(jié)點(diǎn)和尾節(jié)點(diǎn),其中每個(gè)head 和 tail 之間是雙向鏈表.每個(gè)quicklistNode指向一個(gè) ziplist.

struct quicklistNode{
    quicklistNode* prev;    //前一個(gè)節(jié)點(diǎn)
    quicklistNode* next;    //后一個(gè)節(jié)點(diǎn)
    ziplist* zl;            //壓縮列表
    int32 size;             //ziplist大小
    int16 count;            //ziplist 中元素?cái)?shù)量
    int2 encoding;          //編碼形式 存儲 ziplist 還是進(jìn)行 LZF 壓縮儲存
    ...
}

在 quicklist 中每個(gè) ziplist 默認(rèn)大小是 8kb,超出這個(gè)字節(jié)就會增加一個(gè) ziplist.這個(gè)默認(rèn)大小是可配置的,由list-max-ziplist-size決定.

image

上面說到 ziplist 可以使用 LZF 算法壓縮,通過list-compress-depth配置.默認(rèn)情況下quicklist 的壓縮深度是 0,也就是不壓縮.配置為 1 的話代表從頭/尾開始第 1 個(gè)ziplsit 進(jìn)行壓縮.

image

下章預(yù)告,Redis 數(shù)據(jù)結(jié)構(gòu)之 Hash

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肴沫,隨后出現(xiàn)的幾起案子蔗蹋,更是在濱河造成了極大的恐慌,老刑警劉巖宙地,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件用爪,死亡現(xiàn)場離奇詭異活鹰,居然都是意外死亡漏策,警方通過查閱死者的電腦和手機(jī)派哲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掺喻,“玉大人芭届,你說我怎么就攤上這事储矩。” “怎么了喉脖?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵椰苟,是天一觀的道長抑月。 經(jīng)常有香客問我树叽,道長,這世上最難降的妖魔是什么谦絮? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任题诵,我火速辦了婚禮,結(jié)果婚禮上层皱,老公的妹妹穿的比我還像新娘性锭。我一直安慰自己,他們只是感情好叫胖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布草冈。 她就那樣靜靜地躺著,像睡著了一般瓮增。 火紅的嫁衣襯著肌膚如雪怎棱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天绷跑,我揣著相機(jī)與錄音,去河邊找鬼砸捏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛垦藏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掂骏,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼轰驳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芭挽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蠕趁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后辛馆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俺陋,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡豁延,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诱咏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缴挖。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖映屋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棚点,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布瘫析,位于F島的核電站,受9級特大地震影響咸包,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜诉儒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一亏掀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滤愕,春花似錦、人聲如沸间影。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽付燥。三九已至,卻和暖如春键科,著一層夾襖步出監(jiān)牢的瞬間闻丑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工勋锤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侥祭,地道東北人叁执。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓卑硫,卻偏偏與公主長得像蚕断,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子亿乳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Redis的內(nèi)存優(yōu)化 聲明:本文內(nèi)容來自《Redis開發(fā)與運(yùn)維》一書第八章葛假,如轉(zhuǎn)載請聲明。 Redis所有的數(shù)據(jù)都...
    meng_philip123閱讀 18,879評論 2 29
  • 參考來源 Redis的內(nèi)存優(yōu)化 Redis所有的數(shù)據(jù)都在內(nèi)存中聊训,而內(nèi)存又是非常寶貴的資源。對于如何優(yōu)化內(nèi)存使用一直...
    秦漢郵俠閱讀 1,283評論 0 2
  • redis的數(shù)據(jù)結(jié)構(gòu)string,hash挂滓,list,set(集合)赶站,zset(有序集合) 五種數(shù)據(jù)結(jié)構(gòu),但這個(gè)只...
    IT菜鳥學(xué)習(xí)閱讀 1,691評論 0 0
  • 今天我胃酸想括,淇淇自己買早點(diǎn)上學(xué)!我只能躺在床上聽聽音頻主胧,十點(diǎn)胃餓做了稀飯叭首,蒸了粽子和包子踪栋,中午淇淇回來將稀飯...
    齊偉閱讀 168評論 0 0
  • 如果可以,我愿來生一定會做一棵樹夷都。 享雨露陽光,承風(fēng)雨疾風(fēng)冬阳,從一粒種子啟程,享受生命中所有的苦樂悲歡肝陪。用歲月...
    美女米豆閱讀 707評論 4 10