說明
版本 < 3.2 時,使用 linkedlist 和 ziplist,也就是元素少時用 ziplist,元素多時用 linkedlist。
版本 ≥ 3.2時,使用 quicklist。
廣泛用於實現 Redis 的各種功能,列表鍵、發佈與訂閱、慢查詢、監視器等
可以通過 debug object xxx(鍵),中的 encoding 查看使用了什麼結構
- ziplist 對空間的利用率非常高,在數據規模比較小時,耗時相對可接受,但是對於元素比較多或者是單個元素比較長時,插入、彈出的耗時非常大。
- linkedlist 在插入、刪除元素時,元素數量、單個元素的長度對耗時影響小(耗時分佈比較集中),但是空間利用率比較差,特別是數據規模較小時,空間利用率非常差。
- quicklist 結合了二者的優點,首先時間消耗上,數據規模對其影響小,其次是空間利用率,因爲底層使用了ziplist,所以在小規模數據上空間表現也良好。
Redis 對象頭結構體
struct RedisObject {
int4 type; // 4bits
int4 encoding; // 4bits
int24 lru; // 24bits
int32 refcount; // 4bytes
void *ptr; // 8bytes,64-bit system
} robj;
quicklist 快速列表
- 說明: 綜合了 linkedlist 和 ziplist 的特點,同時具有節省內存、插入刪除數據高效的特點
- 結構
typedef struct quicklistNode {
struct quicklistNode *prev; // 前置節點
struct quicklistNode *next; // 後置節點
unsigned char *zl; // 指向壓縮列表
unsigned int sz; // ziplist 的字節總數
unsigned int count : 16; // ziplist 中的元素數量
unsigned int encoding : 2; // 原生字節數組還是 LZF 壓縮存儲 RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
typedef struct quicklist {
quicklistNode *head; // 頭節點
quicklistNode *tail; // 尾節點
unsigned long count; // 元素總數 /* total count of all entries in all ziplists */
unsigned long len; // 節點的個數 /* number of quicklistNodes */
int fill : 16; // 正數爲,單個節點允許的最大數量,負數代表單個節點的內存空間大小 -1:4Kb,-2:8kb... /* fill factor for individual nodes */
unsigned int compress : 16; // 壓縮深度 0 不壓縮 /* depth of end nodes not to compress;0=off */
} quicklist;
- 內部默認單個 ziplist 長度爲 8k 字節,超出了這個字節數,就會新起一個 ziplist。ziplist 的長度由配置參數 list-max-ziplist-size 決定。
- compress 實際深度由配置參數 list-compress-depth 決定。爲了支持快速的 push/pop 操作,quicklist 的首尾兩個 ziplist 不壓縮,此時深度就是 1。如果深度爲 2,就表示 quicklist 的首尾第一個 ziplist 以及首尾第二個 ziplist 都不壓縮。