当前位置: 首页 > news >正文

Redis数据结构ZipList,QuickList,SkipList

目录

1.ZipList

1.2.解析Entry:

1.3Encoding编码

1.4.ZipList连锁更新问题

2.QuickList

SkipList跳表

RedisObject

五种数据类型


1.ZipList

redis中的ZipList是一种紧凑的内存储存结构,主要可以节省内存空间储存小规模数据。是一种特殊的双端链表,有一系列连续的内存组成,可以在任意一端进行压入/弹出操作,而且操作的时间复杂度为O(1)

常见方法:

LPUSH mylist "value1" "value2"    //左边插入
RPUSH mylist "value3" "value4"    //右边插入LPOP mylist    //从链表最左端弹出数据
RPOP mylist    //从链表最右端弹出数据LRANGE mylist 0 2    //获取左边指定范围的数据
LINDEX mylist 0    //获取指定下标数据LLEN mylist    //获取列表长度
zlbyteszltailzllenentry

...

entryentryzlend
属性类型长度用途
zlbytesuint32_t4字节记录整个压缩链表占用的内存字节数
zltailuint32_t4字节这个是偏移量,记录压缩列表尾节点到列表起始地址有多少字节,通过这个偏移量,可以确定尾节点地址
zllenuint16_t2字节记录列表包含的节点数量。最大65534,如果超出也只是65535
entry列表节点不定各个节点的长度由节点保存的内容确定
zlenduint8_t1字节特殊值0xFF(255),用于标记压缩例表的末端
1.2.解析Entry:

ZipList的Entry不像普通链表那样记录前后节点的指针,因为记录前后节点指针需要16字节,大大浪费了内存。所以采用下面的结构来保存。

previous_entry_lengthencoding

content

1.previous_entry_length:前一节点的长度,占1字节 或 5字节

当前一节点长度 < 254字节,采用 1字节保存这个长度值

当前一节点的长度 > 254字节,采用5字节保存这个长度值

2.encoding:编码属性,记录content的数据类型(数字/字符串)及长度,占用1,2,5字节。

3.contents:负责保存具体的内容,可以是数字可以是字符串

注意:ZipList中所有储存长度的数值均采用小端字节序储存,低位在前,高位字节在后。

列如:0x1234,采用小端字节序后就是 0x3412

1.3Encoding编码

encoding编码分为两种:字符串和数字

字符串:encoding以00,01,10开头标识储存的是字符串。

下面长度不同的字符串对应encoding编码格式

举例:储存字符串ab,bc

1.4.ZipList连锁更新问题

ZipList的每个Entry都包含previous_entry_length来记录上一节点大小,长度为1个或5字节。

>>如果前一节点长度 < 254,那么采用1字节保存这个长度值。

>>如果前一节点 >= 254,则采用5字节保存这个长度值。

如果有N个连续的长度为250~253之间的entry,如果不巧有一个扩展那么又可能发生连锁反应,又可能所有都发生连锁更新,新增,删除都可能导致连锁更新发生

总结:

1.压缩列表可以看作连续内存空间的“双向链表“

2.列表的节点之间不是通过指针链接,而是上一节点和本节点长度来寻址,大大节省内存

3.如果数据过多,链表过长,可能影响查询性能

4.增加删除都可能发生连续更新问题


2.QuickList

ZIpList虽然节省内存,但是申请内存必须是连续空间,如果内存占用过多那么申请效率变低

数据量过大超出上限采用分片储存数据,那么这些ZipList如何联系?

Redis3.2版本引入QuickList,是一个双端链表,只不过每个节点都是ZipList

Redis提供配置:list-max-ziplist-size 

如果值是正:代表ZipList允许的最大entry数。

如果值是负:代表每个ZipList的最大内存大小。

-1-2-3-4-5
4kb8kb16kb32kb64kb

QuickList可以控制首尾是否进行压缩,通过配置项list-compress-depth来控制,这个参数是控制首尾不压缩的节点个数。

012
代表首尾节点不压缩首尾各有一个1个不压缩,中间全压缩首尾各有2节点不压缩,中间全压缩

QuickList 和 Quick List Node的结构源码:

QuickList结构图:

QuickList特性:

1.每个节点都是ZipList的双端链表

2.节点采用ZipList,解决传统链表的内存占用

3.控制ZipList大小,解决传统连续内存空间申请问题

4.中间节点可压缩,节省内存


SkipList跳表

是个链表,但不是普通链表,不同节点之间跨度不一样。

1.元素按照升序排列储存

2.节点可能包含多个指针,指针跨度不同

为了更快的找到所需要的元素,SkipList采用这种结构类似于二分查找。

以下是结构源码:

// t_zset.c
typedef struct zskiplist {// 头尾节点指针struct zskiplistNode* header, * tail;// 节点数量unsigned long length;// 最大的索引层级,默认是1int level;
} zskiplist;// t_zset.c
typedef struct zskiplistNode {sds ele; // 节点存储的值double score;// 节点分数,排序、查找用struct zskiplistNode* backward; // 前一个节点指针struct zskiplistLevel {struct zskiplistNode* forward; // 下一个节点指针unsigned long span; // 索引跨度} level[]; // 多级索引数组
} zskiplistNode;

特性:

1.跳表是一个双向链表,每个节点包含存储的值和排序用的socre,用来保存别的节点的ele数组

2.节点按照score值排序,score值一样按照ele字典排序

3.每层指针到下一节点跨度不同,层级越高跨度越大

4.增删改查的效率与红黑树基本一致


RedisObject

在Redis中任意数据类型的键和值都会被封装在一个RedisObject中,也叫做Redis对象。

Redis会根据储存不同的数据类型选择不同的编码格式,共包含11种不同类型。

编号编码方式说明
0OBJ_ENCODING_RAW动态字符串(动态长度,非预分配)
1OBJ_ENCODING_INT长整型(用 long 类型存储)
2OBJ_ENCODING_HT哈希表(字典,基于 dict 实现)
3OBJ_ENCODING_ZIPMAP已废弃的哈希压缩结构
4OBJ_ENCODING_LINKEDLIST双端链表(旧版 List 实现)
5OBJ_ENCODING_ZIPLIST压缩列表(紧凑的二进制结构)
6OBJ_ENCODING_INTSET整数集合(仅存储整数的有序集合)
7OBJ_ENCODING_SKIPLIST跳表(有序集合的底层实现之一)
8OBJ_ENCODING_EMBSTR短字符串(固定长度,预分配内存)
9OBJ_ENCODING_QUICKLIST快速列表(双向链表 + 压缩列表)
10OBJ_ENCODING_STREAMStream 流(消息队列结构)

五种数据类型

String基于简单动态字符串SDS实现,存储上限为512mb,基本编码方式是RAM

List可以从首尾操作列表中的元素,3.2版本后统一采用QuickList来实现List

Set:

1.为了查询效率和唯一性,采用Dict编码,key为存储元素,value统一为null

2.所有数据都是整数,且元素数量不超过set-max-intset-entries,Set会采用IntSet编码

ZSet:

ZSet就是SortedSet,其中每个元素都需指定一个score 和 member值

可以根据score排序,且member必须唯一,可以根据member查询分数

当元素数数量小时,采用ZipList来节省内存,但是需要满足两个条件:

1.元素数量小于 zset_max_ziplist_entries (128)

2.每个元素都小于zset_max_ziplist_value(64)

当数据量大时采用SkipList和HT结构

Hash:

hash底层的编码和ZSet基本一致,只需要把排序有关的SkipList去掉就行。

1.数据量小时,采用ZipList编码节省内存,ZipList中相邻的两个entry保存field和value

2.数据量大时,采用HT编码,就是Dict,触发条件是:元素数量超过512,每个entry超过64字节

http://www.dtcms.com/a/172404.html

相关文章:

  • linux、window安装部署nacos
  • MinIO实现https访问
  • 全局过滤器与局部过滤器: Vue中的文本格式化工具
  • Linux中web服务器的部署及优化
  • 网络安全自动化:找准边界才能筑牢安全防线
  • 2024年408真题及答案
  • 学习路线(机器人软件架构)
  • Linux的web服务器的部署及优化
  • 在 Win10 上如何安装 WSL 2 ?
  • Serverless
  • 网狐飞云娱乐三端源码深度实测:组件结构拆解与部署Bug复盘指南(附代码分析)
  • 告别散乱的 @ExceptionHandler:实现统一、可维护的 Spring Boot 错误处理
  • 字符串匹配 之 拓展 KMP算法(Z算法)
  • 如何选择合适的光源?
  • 【阿里云大模型高级工程师ACP学习笔记】2.9 大模型应用生产实践 (下篇)
  • Python异步编程进阶:深入探索asyncio高级特性
  • 在Ubuntu系统中安装桌面环境
  • 基于机器学习算法预测二手车市场数据清洗与分析平台(源码+定制+讲解) 基于Python的数据挖掘与可视化 二手车数据处理与分析系统开发 (机器学习算法预测)
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】6.1 客户分群分析(RFM模型构建)
  • Electron 架构详解:主进程与渲染进程的协作机制
  • 第一章-Rust入门
  • 系统思考:困惑源于内心假设
  • 硬件工程师面试常见问题(14)
  • 信息安全基石:加解密技术的原理、应用与未来
  • Redis的内存淘汰机制
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】5.1 描述性统计分析(均值/方差/分位数计算)
  • PHP的现代复兴:从脚本语言到企业级服务端引擎的演进之路-优雅草卓伊凡
  • Docker 容器 - Dockerfile
  • [逆向工程]什么是Cheat Engine
  • simulink 外循环与内循环执行流程