|NO.Z.00060|——————————|BigDataEnd|——|Hadoop&Redis.V05|——|Redis.v05|RedisDB结构.v05|结构7种type.v03|
一、压缩列表
### --- 压缩列表
~~~ 压缩列表(ziplist)是由一系列特殊编码的连续内存块组成的顺序型数据结构
### --- 节省内存
~~~ 是一个字节数组,可以包含多个节点(entry)。每个节点可以保存一个字节数组或一个整数。
### --- 压缩列表的数据结构如下:
~~~ zlbytes:压缩列表的字节长度
~~~ zltail:压缩列表尾元素相对于压缩列表起始地址的偏移量
~~~ zllen:压缩列表的元素个数
~~~ entry1..entryX : 压缩列表的各个节点
~~~ zlend:压缩列表的结尾,占一个字节,恒为0xFF(255)

### --- entryX元素的编码结构:
~~~ previous_entry_length:前一个元素的字节长度
~~~ encoding:表示当前元素的编码
~~~ content:数据内容

### --- ziplist结构体如下:
typedef struct zlentry {
unsigned int prevrawlensize; //previous_entry_length字段的长度
unsigned int prevrawlen; //previous_entry_length字段存储的内容
unsigned int lensize; //encoding字段的长度
unsigned int len; //数据内容长度
unsigned int headersize; //当前元素的首部长度,即previous_entry_length字段长度与 encoding字段长度之和。
unsigned char encoding; //数据类型
unsigned char *p; //当前元素首地址
} zlentry;
### --- 应用场景:
~~~ sorted-set和hash元素个数少且是小整数或短字符串(直接使用)
~~~ list用快速链表(quicklist)数据结构存储,而快速链表是双向列表与压缩列表的组合。(间接使用)
二、整数集合
### --- 整数集合
~~~ 整数集合(intset)是一个有序的(整数升序)、存储整数的连续存储结构。
~~~ 当Redis集合类型的元素都是整数并且都处在64位有符号整数范围内(2^64),使用该结构体存储。
127.0.0.1:6379> sadd set:001 1 3 5 6 2
(integer) 5
127.0.0.1:6379> object encoding set:001
"intset"
127.0.0.1:6379> sadd set:004 1 100000000000000000000000000 9999999999
(integer) 3
127.0.0.1:6379> object encoding set:004
"hashtable"
### --- intset的结构图如下:
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
}intset;

### --- 应用场景:
~~~ 可以保存类型为int16_t、int32_t 或者int64_t 的整数值,并且保证集合中不会出现重复元素。
三、快速列表(重要)
### --- 快速列表(重要)
### --- 双向列表(adlist)
~~~ 快速列表(quicklist)是Redis底层重要的数据结构。是列表的底层实现。
~~~ (在Redis3.2之前,Redis采用双向链表(adlist)和压缩列表(ziplist)实现。)
~~~ 在Redis3.2以后结合adlist和ziplist的优势Redis设计出了quicklist。

### --- 双向链表优势:
~~~ 1. 双向:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。
~~~ 2. 普通链表(单链表):节点类保留下一节点的引用。
~~~ 链表类只保留头节点的引用只能从头节点插入删除
~~~ 3. 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,
~~~ 对链表的访问都是以 NULL 结束。环状:头的前一个节点指向尾节点
~~~ 4. 带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。
~~~ 5. 多态:链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值。
### --- 快速列表
~~~ quicklist是一个双向链表,链表中的每个节点时一个ziplist结构。
~~~ quicklist中的每个节点ziplist都能够存储多个数据元素。

### --- quicklist的结构定义如下:
typedef struct quicklist {
quicklistNode *head; // 指向quicklist的头部
quicklistNode *tail; // 指向quicklist的尾部
unsigned long count; // 列表中所有数据项的个数总和
unsigned int len; // quicklist节点的个数,即ziplist的个数
int fill : 16; // ziplist大小限定,由list-max-ziplist-size给定
(Redis设定)
unsigned int compress : 16; // 节点压缩深度设置,由list-compress-depth给定(Redis设定)
} quicklist;
### --- quicklistNode的结构定义如下:
typedef struct quicklistNode {
struct quicklistNode *prev; // 指向上一个ziplist节点
struct quicklistNode *next; // 指向下一个ziplist节点
unsigned char *zl; // 数据指针,如果没有被压缩,就指向ziplist结构,反之指向 quicklistLZF结构
unsigned int sz; // 表示指向ziplist结构的总长度(内存占用长度)
unsigned int count : 16; // 表示ziplist中的数据项个数
unsigned int encoding : 2; // 编码方式,1--ziplist,2--quicklistLZF
unsigned int container : 2; // 预留字段,存放数据的方式,1--NONE,2--ziplist
unsigned int recompress : 1; // 解压标记,当查看一个被压缩的数据时,需要暂时解压,标记此参数为 1,之后再重新进行压缩
unsigned int attempted_compress : 1; // 测试相关
unsigned int extra : 10; // 扩展字段,暂时没用
} quicklistNode;
### --- 数据压缩
~~~ # quicklist每个节点的实际数据存储结构为ziplist,
~~~ 这种结构的优势在于节省存储空间。为了进一步降低ziplist的存储空间,
~~~ 还可以对ziplist进行压缩。Redis采用的压缩算法是LZF。
~~~ 其基本思想是:数据与前面重复的记录重复位置及长度,不重复的记录原始数据。
~~~ # 压缩过后的数据可以分成多个片段,
~~~ 每个片段有两个部分:解释字段和数据字段。quicklistLZF的结构体如下:
typedef struct quicklistLZF {
unsigned int sz; // LZF压缩后占用的字节数
char compressed[]; // 柔性数组,指向数据部分
} quicklistLZF;
### --- 应用场景
~~~ 列表(List)的底层实现、发布与订阅、慢查询、监视器等功能。
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
bdv012-redis
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」