首页 > 数据库 >Redis笔记——底层数据结构之压缩列表

Redis笔记——底层数据结构之压缩列表

时间:2024-06-01 19:04:15浏览次数:23  
标签:字节 ZIPLIST prevlen Redis 列表 element 数据结构 数据 节点

是什么?

        本质上就是紧凑的列表

        压缩列表在 Redis 中有两种编码方式,分别是 ZIPLISTLISTTPACK。LISTPACK 从 Redis 5.0 引入,直至 Redis 7.0 完全替换了 ZIPLIST,可以看作是 ZIPLIST 的进阶版。

有什么作用?

        在 List 文章中,提到了 ZIPLIST 是 LIST 的底层数据结构之一,提供紧凑型的数据存储,能节约内存(节省链表指针开销)。在数据量较少时,遍历访问性能好(连续且缓存命中率高)。

ZIPLIST的结构

* ZIPLIST 结构如下:
<zlbytes><zltail><zllen><entry><entry>...<entry><zlend>

* 字段含义:
zlbytes:占用4字节,表示该 ZIPLIST 总共占用了多少字节。
zltail:占用4字节,表示最后一个 entry 节点相对于起始指针的偏移量,可快速定位尾部节点,如果
    没有尾部节点则定为到 zlend。
zllen:占用2字节,表示共有多少个 entry 节点。
entry:数据节点。
zlend:占用1字节,一个特殊的节点,表示 ZIPLIST 的结束,值为255。

* 数据节点 entry 的结构如下:
<prevlen><encoding><entry-data>

* 字段含义:
prevlen:上一个数据节点的长度。当前数据节点起始地址 - prevlen 可以快速定位到上一个数据节点
    的起始地址。通过 prevlen 实现从后向前操作。
I、  255 是特殊字符,被 zlend 节点占用了。
II、 如果上一个数据节点大小 < 254字节,那当前数据节点的 prevlen 属性需要用1字节记录该长度值。
III、如果上一个数据节点大小 ≥ 254字节,那当前数据节点的 prevlen 属性需要用5字节记录该长度值。
此时该5个字节的第一个字节值为 11111110 即 254,标志这是个5个字节的 prevlen 属性,剩下的4个
字节用于记录该长度值。
encoding:编码类型,同时还记录着 entry-data 属性值的长度。
entry-data:实际的数据。

操作详析

查询 ZIPLIST 数据总量

        因为 ZIPLIST 本身通过 zllen 节点存储了节点数量,所以通常情况下时间复杂度为O(1)

        需要注意的是,因为 zllen 节点本身只占用2个字节,表示长度的上限就是65535。当数据节点超过65535个zllen 为0,此时需要遍历数据节点,以获取真正的长度,时间复杂度为O(n)。

查询指定数据节点

        需要遍历数据节点,时间复杂度为O(n)

更新数据

        ZIPLIST 提供头尾增减的能力,在头部增加节点会导致后续全部节点的后移,所以平均时间复杂度看作O(n)

        ZIPLIST 的更新操作可能导致连锁更新,这个连锁更新与刚刚的增加节点导致的节点后移不是同一个概念。

        比如在头部新增一个大小 > 254字节的数据节点,此时第二个数据节点的 prevlen 需要记录第一个节点的长度,原本 1 字节的 prevlen 膨胀为5字节,其本身数据节点大小也随之改变。所以当这个新的数据节点插入导致的后续节点位移完成后,还需要逐步更新迭代,这种现象称为连锁更新。时间复杂度是O(n^2),在 Redis 6.2 中已经优化为O(n)。

LISTPACK优化

连锁更新的根本原因

        ZIPLIST 作为 LIST 的底层数据结构,需要支持其双端操作的特性(既可以从前向后访问,也可以从后向前访问)。上面我们上面我们提到了 ZIPLIST 的数据节点的结构。

<prevlen><encoding><entry-data>

        prevlen 属性用于记录上一个数据节点的长度,基于此来实现从后向前访问数据节点。可以说 ZIPLIST 连锁更新问题就是因为 prevlen 导致的。我们需要一种不借助 prevlen,还能找到上一节点的起始位置的方法。

LISTPACK的解决方案
* LISTPACK 结构如下:
<encoding-type><element-data><element-tot-len>

* 字段含义:
encoding-type:编码类型。
element-data:数据内容。
element-tot-len:存储整个数据节点,除了它自身之外的长度。

        找到上一节点的关键就在于 element-tot-len。element-tot-len 所占用的每一个字节的第一个 bit 用于标识是否结束,0是结束,1是继续,剩下的7个 bit 用来存储数据大小

        当我们从后向前访问数据节点时,我们可以从后向前查找前一个数据节点的 element-tot-len 的每一个字节,直至找到其结束标识,这样就可以算出前一个数据节点的起始位置了。

        举个栗子:上个节点的 element-tot-len 为 00000001 10000100,从后向前查询,根据结束标志0,确认 element-tot-len 属性为2字节,上个节点总大小(不包含 element-tot-len )为 0000001 0000100 ==> 132字节,即再向前走132字节,就到了该节点的起始位置了。

标签:字节,ZIPLIST,prevlen,Redis,列表,element,数据结构,数据,节点
From: https://blog.csdn.net/Jellylove0511/article/details/139377923

相关文章

  • 深入解析力扣170题:两数之和 III - 数据结构设计(哈希表与双指针法详解及模拟面试问答)
    在本篇文章中,我们将详细解读力扣第170题“两数之和III-数据结构设计”。通过学习本篇文章,读者将掌握如何设计一个数据结构来支持两种操作,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释和ASCII图解,以便于理解。问题描述力扣第170题“两数之和III......
  • 数据结构复习笔记4:队列,双端队列,循环队列
    1.队列概念和特点        队列是⼀种特殊的线性表,特殊之处就在于它只允许在表的前端进⾏删除操作,在表的后端进⾏插⼊操作。和栈⼀样,队列也是⼀种操作受到限制的线性表。进⾏插⼊操作的端称之为队尾,进⾏删除操作的端称之为队头。队列中没有队列的时候,称之为空队列。......
  • 拿下列表和元组只要一篇就够了
    一.列表的定义Python中的列表(List)是一种有序、可变的序列类型,可以使用方括号来表示一个列表,其中各个元素之间使用逗号分隔。列表中的每个元素可以是不同类型的数据,如整数、字符串、浮点数等。#定义一个多元素的列表ls=[1,2,'hello',3.2,[2,8,'hello']]print(ls)......
  • 【Redis】保证redis的高并发高可用的几种策略
    保证Redis的高并发高可用性需要从多方面入手,包括架构设计、配置优化、监控和维护。以下是一些具体的策略和方法:1.Redis集群模式Redis集群模式通过将数据分片分布到多个节点上来实现高并发和高可用性。分片:将数据分布到多个节点,减少单个节点的负载。主从复制:每个主节......
  • 3.redis数据库
    Redis简介和使用:简介:Redis是一个基于内存的key-value结构数据库;基于内存存储,读写性能高;适合存储热点数据(热点商品、资讯、新闻);企业应用广泛;使用:启动服务端,命令提示符处于Redis的安装目录下,输入服务端的命令和Redis的配置文件;启动服务端命令:redis-server.exeredis.win......
  • redis 缓存 singlefly 查询
    正常缓存没有数据时会先从DB取数据来回填缓存,而如果瞬间查询过多或者缓存利用率过低。singlefly当瞬间过多查询到缓存的空值时就会一起去查询数据库,带给数据库压力变大。这里不能直接用mutex,如果用了拿不到资源的会自旋等待,拿到后继续查DB,用mutex可能会出现整个逻辑处于一直......
  • 【数据结构】二叉树-堆(下)-链式二叉树
    个人主页~二叉树-堆(上)栈和队列二叉树四、堆的代码实现Heap.hHeap.ctest.c五、堆的应用堆排序思想进行排序六、二叉树链式结构的实现BTree.hBTree.ctest.c四、堆的代码实现Heap.h#pragmaonce#include<stdio.h>#include<stdlib.h>#include<assert.h>......
  • 【数据结构】二叉树
    【数据结构】二叉树树树的概念树的相关概念树的注意事项左孩子右兄弟表示法树实际中的应用二叉树二叉树的概念二叉树的注意事项特殊二叉树满二叉树完全二叉树二叉树的性质二叉树的存储形式顺序存储链式存储二叉树链式结构简单初始化二叉树的遍历前序遍历中序遍历后续......
  • Session+Redis,Token+Redis,JWT+Redis,用户身份认证,到底选择哪种更合适?
    1三中方案的比较在选择Session+Redis、Token+Redis、JWT+Redis这三种用户身份认证方案时,我们需要考虑各自的优势、劣势以及应用场景。以下是对这三种方案的详细分析和比较:1.Session+Redis优势:Session登录是一种在Web应用程序中用于跟踪用户状态的机制,通过在服务器端存储......
  • windows安装redis
    1、下载: Releases·microsoftarchive/redis(github.com)   2、解压Redis安装包 3、注册RedisWindows服务进入Redis安装包目录,执行如下的命令,安装服务redis-server.exe--service-installredis.windows.conf--service-nameredisserver1--loglevelverbose......