壓縮列表(ziplist)是列表鍵和哈希鍵的底層實(shí)現(xiàn)之一甘邀。
當(dāng)一個(gè)列表鍵只包含少量列表項(xiàng)伟骨, 并且每個(gè)列表項(xiàng)要么就是小整數(shù)值仔夺, 要么就是長(zhǎng)度比較短的字符串咆畏, 那么 Redis 就會(huì)使用壓縮列表來(lái)做列表鍵的底層實(shí)現(xiàn)南捂。
比如說(shuō), 執(zhí)行以下命令將創(chuàng)建一個(gè)壓縮列表實(shí)現(xiàn)的列表鍵:
redis> RPUSH lst 1 3 5 10086 "hello" "world"
(integer) 6
redis> OBJECT ENCODING lst
"ziplist"
因?yàn)榱斜礞I里面包含的都是 1 鳖眼、 3 、 5 嚼摩、 10086 這樣的小整數(shù)值钦讳, 以及 "hello" 、 "world" 這樣的短字符串枕面。
另外愿卒, 當(dāng)一個(gè)哈希鍵只包含少量鍵值對(duì), 并且每個(gè)鍵值對(duì)的鍵和值要么就是小整數(shù)值潮秘, 要么就是長(zhǎng)度比較短的字符串琼开, 那么 Redis 就會(huì)使用壓縮列表來(lái)做哈希鍵的底層實(shí)現(xiàn)。
舉個(gè)例子枕荞, 執(zhí)行以下命令將創(chuàng)建一個(gè)壓縮列表實(shí)現(xiàn)的哈希鍵:
redis> HMSET profile "name" "Jack" "age" 28 "job" "Programmer"
OK
redis> OBJECT ENCODING profile
"ziplist"
壓縮列表是 Redis 為了節(jié)約內(nèi)存而開(kāi)發(fā)的柜候, 由一系列特殊編碼的連續(xù)內(nèi)存塊組成的順序型(sequential)數(shù)據(jù)結(jié)構(gòu)。
一個(gè)壓縮列表可以包含任意多個(gè)節(jié)點(diǎn)(entry)躏精, 每個(gè)節(jié)點(diǎn)可以保存一個(gè)字節(jié)數(shù)組或者一個(gè)整數(shù)值渣刷。
壓縮表的構(gòu)成
圖 7-1 展示了壓縮列表的各個(gè)組成部分, 表 7-1 則記錄了各個(gè)組成部分的類(lèi)型矗烛、長(zhǎng)度辅柴、以及用途。
- 列表 zlbytes 屬性的值為 0x50 (十進(jìn)制 80)瞭吃, 表示壓縮列表的總長(zhǎng)為 80 字節(jié)碌嘀。
- 列表 zllen 屬性的值為 0x3 (十進(jìn)制 3), 表示壓縮列表包含三個(gè)節(jié)點(diǎn)歪架。
- 列表 zltail 屬性的值為 0x3c (十進(jìn)制 60)股冗, 這表示如果我們有一個(gè)指向壓縮列表起始地址的指針 p , 那么只要用指針 p 加上偏移量 60 和蚪, 就可以計(jì)算出表尾節(jié)點(diǎn) entry3 的地址魁瞪。
圖 7-3 展示了另一個(gè)壓縮列表示例:
- 列表 zlbytes 屬性的值為 0xd2 (十進(jìn)制 210)穆律, 表示壓縮列表的總長(zhǎng)為 210 字節(jié)。
- 列表 zltail 屬性的值為 0xb3 (十進(jìn)制 179)导俘, 這表示如果我們有一個(gè)指向壓縮列表起始地址的指針 p 峦耘, 那么只要用指針 p 加上偏移量 179 , 就可以計(jì)算出表尾節(jié)點(diǎn) entry5 的地址旅薄。
- 列表 zllen 屬性的值為 0x5 (十進(jìn)制 5)辅髓, 表示壓縮列表包含五個(gè)節(jié)點(diǎn)。
壓縮表節(jié)點(diǎn)的構(gòu)成
每個(gè)壓縮列表節(jié)點(diǎn)都由 previous_entry_length 少梁、 encoding 洛口、 content 三個(gè)部分組成
previous_entry_length
節(jié)點(diǎn)的 previous_entry_length 屬性以字節(jié)為單位, 記錄了壓縮列表中前一個(gè)節(jié)點(diǎn)的長(zhǎng)度凯沪。
previous_entry_length 屬性的長(zhǎng)度可以是 1 字節(jié)或者 5 字節(jié):
- 如果前一節(jié)點(diǎn)的長(zhǎng)度小于 254 字節(jié)第焰, 那么 previous_entry_length 屬性的長(zhǎng)度為 1 字節(jié): 前一節(jié)點(diǎn)的長(zhǎng)度就保存在這一個(gè)字節(jié)里面。
- 如果前一節(jié)點(diǎn)的長(zhǎng)度大于等于 254 字節(jié)妨马, 那么 previous_entry_length 屬性的長(zhǎng)度為 5 字節(jié): 其中屬性的第一字節(jié)會(huì)被設(shè)置為 0xFE(十進(jìn)制值 254)挺举, 而之后的四個(gè)字節(jié)則用于保存前一節(jié)點(diǎn)的長(zhǎng)度。
因?yàn)楣?jié)點(diǎn)的 previous_entry_length 屬性記錄了前一個(gè)節(jié)點(diǎn)的長(zhǎng)度烘跺, 所以程序可以通過(guò)指針運(yùn)算湘纵, 根據(jù)當(dāng)前節(jié)點(diǎn)的起始地址來(lái)計(jì)算出前一個(gè)節(jié)點(diǎn)的起始地址。
encoding
節(jié)點(diǎn)的 encoding 屬性記錄了節(jié)點(diǎn)的 content 屬性所保存數(shù)據(jù)的類(lèi)型以及長(zhǎng)度
content
節(jié)點(diǎn)的 content 屬性負(fù)責(zé)保存節(jié)點(diǎn)的值滤淳, 節(jié)點(diǎn)值可以是一個(gè)字節(jié)數(shù)組或者整數(shù)梧喷, 值的類(lèi)型和長(zhǎng)度由節(jié)點(diǎn)的 encoding 屬性決定。