redis底层数据结构之ziplist

news2024/11/18 15:37:24

目录

    • 一、概述
    • 二、ziplist结构
    • 三、Entry结构
    • 四、为什么ZipList特别省内存
    • 五、ziplist的缺点

redis底层数据结构已完结👏👏👏:

  • ☑️redis底层数据结构之SDS
  • ☑️redis底层数据结构之ziplist
  • ☑️redis底层数据结构之quicklist
  • ☑️redis底层数据结构之Dict
  • ☑️redis底层数据结构之IntSet
  • ☑️redis底层数据结构之ZSkipList

一、概述

一种连续内存空间存储的顺序数据结构,每个元素可以是字符串或整数。优点:节省内存空间。适用于存储小规模的列表或有序集合。缺点:修改操作可能引发连锁更新,影响性能。使用场景: 在列表键元素较少或元素都是小整数时使用。

在这里插入图片描述

二、ziplist结构

(直达源码–>src/ziplist.c)

  • Header(头部): 包含了ziplist的总字节长度、尾部(最后一个元素)的偏移量,以及ziplist中元素的数量。这些信息有助于快速地访问ziplist的基本属性和迅速找到ziplist的尾部。
  • Entry(项&条目): 每个项可以存储一个整数或者一个字符串。
  • End(结束符): 一个特定的字节(通常是0xFF),标记着ziplist的末尾,确保了ziplist结构的正确解析和遍历的终止。
* ZIPLIST OVERALL LAYOUT
* ======================
*
* The general layout of the ziplist is as follows:
*
* <zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend>
*
* NOTE: all fields are stored in little endian, if not specified otherwise.
*
* <uint32_t zlbytes> is an unsigned integer to hold the number of bytes that
* the ziplist occupies, including the four bytes of the zlbytes field itself.
* This value needs to be stored to be able to resize the entire structure
* without the need to traverse it first.
*
* <uint32_t zltail> is the offset to the last entry in the list. This allows
* a pop operation on the far side of the list without the need for full
* traversal.
*
* <uint16_t zllen> is the number of entries. When there are more than
* 2^16-2 entries, this value is set to 2^16-1 and we need to traverse the
* entire list to know how many items it holds.
*
* <uint8_t zlend> is a special entry representing the end of the ziplist.
* Is encoded as a single byte equal to 255. No other normal entry starts
* with a byte set to the value of 255.

三、Entry结构

  • Previous Entry Length(前一项的长度): 存储前一项的长度,使得ziplist可以被双向遍历。
  • Encoding(编码): 指定了存储的值是整数还是字符串,以及使用了哪一种格式或长度。
  • Content(内容): 实际存储的数据,可以是一个整数的二进制表示,或者是一个字符串的字节序列。
* ZIPLIST ENTRIES
* ===============
*
* Every entry in the ziplist is prefixed by metadata that contains two pieces
* of information. First, the length of the previous entry is stored to be
* able to traverse the list from back to front. Second, the entry encoding is
* provided. It represents the entry type, integer or string, and in the case
* of strings it also represents the length of the string payload.
* So a complete entry is stored like this:
*
* <prevlen> <encoding> <entry-data>

在entry中存储的是比较小的int类型时,encoding和entry-data会合并一起表示,此时会没有entry-data字段

* Sometimes the encoding represents the entry itself, like for small integers
* as we'll see later. In such a case the <entry-data> part is missing, and we
* could have just:
*
* <prevlen> <encoding>

前一个entry长度prevlen编码方式:如果这个长度小于 254 字节,它只会消耗一个字节,将长度表示为无符号 8 位整数。 当长度大于等于254时,会消耗5个字节。 第一个字节设置为 254 (FE) 以指示后面有更大的值。 其余 4 个字节以前一个条目的长度为值。

* So practically an entry is encoded in the following way:
*
* <prevlen from 0 to 253> <encoding> <entry>
*
* Or alternatively if the previous entry length is greater than 253 bytes
* the following encoding is used:
*
* 0xFE <4 bytes unsigned little endian prevlen> <encoding> <entry>

encoding字段内容:条目的encoding字段取决于条目的内容。 当条目是字符串时,encoding第一个字节的前 2 位将保存用于存储字符串长度的编码类型,后面是字符串的实际长度。 当条目是整数时,encoding前 2 位都设置为 1。接下来的 2 位用于指定此标头之后将存储哪种整数。 不同类型和编码的概述如下。 第一个字节始终足以确定条目的类型。

* |00pppppp| - 1 byte
*      String value with length less than or equal to 63 bytes (6 bits).
*      "pppppp" represents the unsigned 6 bit length.
* |01pppppp|qqqqqqqq| - 2 bytes
*      String value with length less than or equal to 16383 bytes (14 bits).
*      IMPORTANT: The 14 bit number is stored in big endian.
* |10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes
*      String value with length greater than or equal to 16384 bytes.
*      Only the 4 bytes following the first byte represents the length
*      up to 2^32-1. The 6 lower bits of the first byte are not used and
*      are set to zero.
*      IMPORTANT: The 32 bit number is stored in big endian.
* |11000000| - 3 bytes
*      Integer encoded as int16_t (2 bytes).
* |11010000| - 5 bytes
*      Integer encoded as int32_t (4 bytes).
* |11100000| - 9 bytes
*      Integer encoded as int64_t (8 bytes).
* |11110000| - 4 bytes
*      Integer encoded as 24 bit signed (3 bytes).
* |11111110| - 2 bytes
*      Integer encoded as 8 bit signed (1 byte).
* |1111xxxx| - (with xxxx between 0001 and 1101) immediate 4 bit integer.
*      Unsigned integer from 0 to 12. The encoded value is actually from
*      1 to 13 because 0000 and 1111 can not be used, so 1 should be
*      subtracted from the encoded 4 bit value to obtain the right value.
* |11111111| - End of ziplist special entry.
*
* Like for the ziplist header, all the integers are represented in little
* endian byte order, even when this code is compiled in big endian systems.

四、为什么ZipList特别省内存

  • ziplist节省内存是相对于普通的list来说的,如果是普通的数组,那么它每个元素占用的内存是一样的且取决于最大的那个元素(很明显它是需要预留空间的);
  • 所以ziplist在设计时就很容易想到要尽量让每个元素按照实际的内容大小存储,所以增加encoding字段针对不同的encoding来细化存储大小
  • 这时候还需要解决的一个问题是遍历元素时如何定位下一个元素呢?在普通数组中每个元素定长,所以不需要考虑这个问题;但是ziplist中每个data占据的内存不一样,所以为了解决遍历,需要增加记录上一个元素的length,所以增加了prelen字段

五、ziplist的缺点

  • 不预留内存空间:ziplist 不预留额外的内存空间,在写操作时可能需要频繁进行内存分配和释放操作,影响性能。

  • 立即缩容:在移除节点后,ziplist 立即缩容,可能导致频繁的内存分配和释放操作。

  • 链式扩容:节点如果扩容,可能导致节点占用的内存增长,并且在超过一定字节后,可能会导致链式扩容。链式扩容的时间复杂度为 O(N),虽然在大多数情况下概率较小,但在恶劣情况下会导致性能下降。

    链式扩容(级联更新)这种现象发生在 ziplist 数据结构中,主要是因为 ziplist 存储了关于前一个元素长度的元数据信息。当一个元素被插入或修改导致其长度增加,并且这个长度增加导致存储前一个元素长度的空间(prevlen)不足以容纳新的长度时,就需要对当前元素进行重新分配以适应长度的变化。这种重新分配可能会影响到相邻的元素,导致它们也需要进行重新分配来适应自己前一个元素的长度变化,从而形成一种“级联”效应。级联更新是 ziplist 的一个潜在缺陷,因为它可能会导致对多个连续元素进行重复的内存分配操作,从而影响性能。这是在 Redis 的后续版本中引入 listpack 作为替代的重要原因之一,listpack 设计上试图减少这种级联更新的可能性,提高数据操作的效率。

    综上所述,尽管 ziplist 能够有效地节省内存空间,但在写操作频繁、节点删除较多或节点扩容较大时,可能会出现性能问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1621099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ETL工具-nifi干货系列 第十六讲 nifi Process Group实战教程,一文轻松搞定

1、目前nifi系列已经更新了10多篇教程了&#xff0c;跟着教程走的同学应该已经对nifi有了初步的解&#xff0c;但是我相信同学们应该有一个疑问&#xff1a;nifi设计好的数据流列表在哪里&#xff1f;如何同时运行多个数据流&#xff1f;如启停单个数据流&#xff1f; 带着这些…

第二期书生浦语大模型训练营第四次笔记

大模型微调技术 大模型微调是一种通过在预训练模型的基础上&#xff0c;有针对性地微调部分参数以适应特定任务需求的方法。 微调预训练模型的方法 微调所有层&#xff1a;将预训练模型的所有层都参与微调&#xff0c;以适应新的任务。 微调顶层&#xff1a;只微调预训练模型…

Pandas数据分析小技巧

Pandas数据分析小技巧&#xff1a;提升数据处理效率与准确性的秘诀 Pandas是一个强大的Python数据分析库&#xff0c;它提供了快速、灵活且富有表现力的数据结构&#xff0c;使得数据清洗、转换、分析等操作变得简单而高效。本文将介绍一些Pandas数据分析的小技巧&#xff0c;…

年如何在不丢失数据的情况下解锁锁定的 Android 手机?

当您忘记密码、PIN 码或图案并且想要解锁 Android 手机时&#xff0c;您可能会丢失 Android 手机上的数据。但您无需再担心&#xff0c;因为在这里&#xff0c;我们想出了几种解锁锁定的 Android 手机而不丢失数据的方法。 方法 1. 使用 Android Unlock 解锁锁定的 Android 且不…

【上海大学计算机组成原理实验报告】四、指令系统实验

一、实验目的 了解指令结构、PC寄存器的功能和指令系统的基本工作原理。 学习设计指令的方法。 二、实验原理 根据实验指导书的相关内容&#xff0c;对于部分使用频率很高&#xff0c;且只用几条微指令即可完成的简单操作&#xff0c;可以把这部分简单操作的微指令序列固定下…

mfc140.dll丢失如何修复,分享多种有效的修复方法

在日常操作和使用电脑的过程中&#xff0c;我们可能会遇到一种较为常见的问题&#xff0c;即在尝试启动或运行某个应用程序时&#xff0c;系统突然弹出一个错误提示窗口&#xff0c;明确指出“mfc140.dll文件丢失”。这个mfc140.dll实际上是一个动态链接库文件&#xff08;DLL&…

linux运行ant 报错 Unable to locate tools.jar【已解决】

linux安装 ant 运行时报错 Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/lib/tools.jar 原因 已安装的jdk只有运行环境&#xff0c;没有tool.jar&#xff0c;而ant运行需要java开发环境&#xff0c;因…

不可思议!我的AI有道英语字典助手竟然与百度千帆AI应用创意挑战赛K12教育主题赛榜首作品差之毫厘

目录 一、前言二、效果对比三、优化《AI英语词典》提示词四、其他获奖作品链接 一、前言 今天看百度千帆AI原生应用创意挑战赛——K12教育主题赛&#xff0c;发现第一名的《我爱记单词》和我早两天发布的一篇《AI英语词典》的想法不谋而合。当时我们应该都是互相不知道对方的&a…

软件游戏缺失d3dcompiler_43.dll怎么修复?分享多种靠谱的解决方法

在我们日常频繁地操作和使用电脑的过程中&#xff0c;时常会遇到一些突发的技术问题。其中一种常见的情况是&#xff0c;在尝试启动或运行某个应用程序时&#xff0c;系统会弹出一个错误提示窗口&#xff0c;明确指出当前电脑环境中缺少了一个至关重要的动态链接库文件——d3dc…

Mysql全局优化总结

Mysql全局优化总结 从上图可以看出SQL及索引的优化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我们要在这块花更多时间 服务端系统参数 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_connections…

【MATLAB源码-第197期】基于matlab的粒子群算法(PSO)结合人工蜂群算法(ABC)无人机联合卡车配送仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于粒子群优化&#xff08;PSO&#xff09;算法的无人机联合卡车配送系统是一个高效的物流配送策略&#xff0c;旨在优化配送过程中的成本、时间和资源利用率。该系统融合了无人机和卡车的配送能力&#xff0c;通过智能算法…

MT2041 三角形的个数

思路&#xff1a;找规律&#xff0c;推公式 4等分&#xff1a; 头朝上的三角形&#xff1a; 边长为1&#xff1a;1234s1&#xff1b; 边长为2&#xff1a;123s2&#xff1b; 边长为3&#xff1a;12s3&#xff1b; 边长为4&#xff1a;1s4&#xff1b; 即si12...n-i1(n-i2)*(n-i…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 3 - 4节&#xff09; P3《开发准备-了解ArkTS》 鸿蒙开发主要是用来开发移动端应用的。 以前我们开发移动端应用的代码&#xff…

如何把视频中的画面保存为图片?免费的工具不用白不用

在数字化时代&#xff0c;截取视频中的珍贵瞬间成为了人们创作、分享和保存回忆的重要方式。 那么&#xff0c;如何迅速捕捉视频中的精彩画面&#xff0c;留存美好瞬间呢&#xff1f;有人说直接截图就可以&#xff0c;如果直接截图就可以&#xff0c;小编就不用写这篇文章了&a…

Tomcat源码解析——一次请求的处理流程

在上一篇文章中&#xff0c;我们知道Tomcat在启动后&#xff0c;会在Connector中开启一个Acceptor(接收器)绑定线程然后用于监听socket的连接&#xff0c;那么当我们发出请求时&#xff0c;第一步也就是建立TCP连接&#xff0c;则会从Acceptor的run方法处进入。 Acceptor&…

29 OpenCV 图像距

文章目录 距的概念API函数示例 距的概念 距的概念 API函数 moments( InputArray array,//输入数据 bool binaryImagefalse // 是否为二值图像 )contourArea( InputArray contour,//输入轮廓数据 bool oriented// 默认false、返回绝对值)arcLength( InputArray curve…

springboot结合elasticJob

先说一说什么是elasticJob。 ElasticJob是一个分布式任务调度的解决方案&#xff0c;它由俩个相互独立的子项目Elastic-job-lite和Elastic- job-cloud组成。 任务调度&#xff1a;是指系统为了自动完成特定任务&#xff0c;在任务的特定时刻去执行任务的过程。 分布式&#xf…

BUUCTF---misc---[SWPU2019]我有一只马里奥

1、下载附件是一个.exe文件 2、运行之后可以看到桌面生成了1.txt文件&#xff0c;文件里面有如下内容 3、经过信息搜索&#xff1a;NTFS&#xff08;New Technology File System&#xff09;是一种由Microsoft开发的专有日志文件系统。根据它的提示&#xff0c;应该是把flag.tx…

安装Fake UserAgent 库的方法最终解答!_Python库

安装Python库Fake UserAgent 我的环境&#xff1a;Window10&#xff0c;Python3.7&#xff0c;Anaconda3&#xff0c;Pycharm2023.1.3 Fake UserAgent Fake UserAgent 是一个Python库&#xff0c;用于生成随机或特定的用户代理&#xff08;UserAgent&#xff09;字符串。用户…

C++:模板(初级)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;模板&#xff08;初级&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞…