redis底层数据结构之ziplist

目录

    • 一、概述
    • 二、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 能够有效地节省内存空间,但在写操作频繁、节点删除较多或节点扩容较大时,可能会出现性能问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker的资源控制管理——Cgroups

目录 引言&#xff1a; 一、CPU资源控制 1、简介 2、cgroup的四大功能&#xff1a; ①资源限制&#xff1a; ②优先级分配&#xff1a; ③资源统计&#xff1a; ④任务控制&#xff1a; 3、设置cpu使用率上限 4、查看CPU默认配置&#xff1a; 5、CPU压力测试 6、设…

H264编码标准中游程编码应用介绍

H264编码标准 H.264编码标准&#xff0c;也被称作MPEG-4 AVC&#xff08;Advanced Video Coding&#xff09;&#xff0c;是一种被广泛使用的数字视频压缩标准。它由国际电信联盟&#xff08;ITU-T&#xff09;和国际标准化组织&#xff08;ISO&#xff09;共同开发&#xff0…

C++核心编程——4.5 运算符重载

4.5.0 运算符重载概念 对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 4.5.1 加号运算符重载 作用&#xff1a;实现两个自定义数据类型相加的运算 class Person { public:Person() {};Person(int a, int b){this->m_A a;this…

Bayes判别:统计学中的经典分类方法

在统计和机器学习领域&#xff0c;Bayes判别是一个基于概率理论的强大工具&#xff0c;用于解决分类问题。它基于Bayes定理&#xff0c;通过计算和比较后验概率来进行决策。这种方法在处理不确定性和不完整数据时表现尤为出色&#xff0c;因此在医学诊断、邮件过滤、语音识别等…

《十》Qt各种对话框之QFontDialog

QFontDialog 在介绍 QFontDialog 对话框之前&#xff0c;我们先简单介绍一下 QFont 字体类。QFont 主要用于控制文本显示的字体&#xff0c;字体主要有四大属性&#xff1a;①字体家族 family 决定字体外观家族&#xff0c;比如宋体、楷体等&#xff1b; ②字号 pointSize &am…

css文字和span在一行对不齐

1.需求背景 父盒子中有两个span&#xff0c;但是span中的文字对不齐。如下图&#xff0c;明显右边的文字偏高 处理后的效果&#xff08;已经对齐&#xff0c;图中标记的是基本的div结构&#xff09;&#xff1a; 2.该问题出现的原因&#xff1a; span1设置的高度比span2内…

thsi指针用法总结

1 c类对象中的变量和函数是分开存储的 2 所以对象共用一份成员函数&#xff0c;类的大小是指非静态的成员变量&#xff1b; this 完成链式操作 const 修饰成员函数

【Java 解析全国详细地址】Java 利用正则表达式完美解析全国省市区地址

这里写自定义目录标题 Java使用正则解析省市区/县 具体地址问题场景上demo运行结果 Java使用正则解析省市区/县 具体地址 问题场景 OCR识别营业执照 获取详细地址并拆分 上demo import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import j…

使用API有效率地管理Dynadot域名,自查账户信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

日本岛津电子天平UW UX 系列series 精密电子天平Shimadzu使用说明

日本岛津电子天平UW UX 系列series 精密电子天平Shimadzu使用说明

2024春季春日主题活动策划方案

2024解冻派对“春日浪漫”主题活动策划方案-32P 方案页码&#xff1a;32页 文件格式&#xff1a;pptx 方案简介&#xff1a; 春来一季&#xff0c;新生欢喜 花香丨微风丨阳光 活动唤起【春日浪漫记忆】&#xff01; 年轻人不一样的派对活动 可以与朋友/小朋友/家人互动…

MT3030 天梯赛

跟MT3029战神小码哥类似&#xff0c;都是贪心堆。注意开long long 这里的堆顶为战斗力最小的&#xff0c;便于贪心的反悔操作。先按容忍度从大到小排序&#xff08;q中总容忍度取决于最小的容忍度&#xff09;&#xff0c;再向q中存数&#xff0c;存到不能容忍之后再把堆顶踢出…

最简单也最复杂的德语动词,柯桥德语培训

德语人一定遇到过这个难题&#xff1a;ie组合到底发什么音&#xff1f; 说起haben&#xff0c;大家可能第一感觉是“这么简单的动词也要讲&#xff1f;不就是‘拥有’的意思吗&#xff1f;” 没错&#xff0c;haben的基本含义是“拥有&#xff0c;包含”&#xff0c;但是在某些…

Vue3后台管理系统推荐

目录 项目概述 &#x1f35f; 项目展示 功能特点 &#x1f957; 结语 &#x1f4a8; 项目概述 &#x1f35f; 基于Vue 3框架与Element-Plus UI组件库技术精心构建的后端管理模板。该模板系统已成功实现一个基础的权限管理模块&#xff0c;宗旨在于为追求高效二次开发的开发…

制作一个RISC-V的操作系统十四-任务同步和锁

文章目录 并发与同步临界区和锁锁死锁解决死锁自旋锁&#xff08;spin lock&#xff09;原子性问题原子操作实现amoswap.w.aq例子 另一种方法自旋锁的注意事项代码其他同步技术 并发与同步 控制流&#xff1a;可理解为任务或进程 中断也可以理解为一个切换到另一个任务&#…

【Linux网络】DHCP原理与配置

目录 一、DHCP工作原理 1.了解DHCP服务 2.使用DHCP的好处 3.DHCP的分配方式 二、DHCP的租约过程 三、DHCP场景应用实验 一、DHCP工作原理 1.了解DHCP服务 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09; 由Internet工作…

<计算机网络自顶向下> 无连接传输UDP

UDP&#xff1a;User Datagram Protocol “尽力而为”的服务 报文可能丢掉或者乱序好处&#xff1a; 效率高&#xff08;不建立连接无拥塞控制和流量控制【应用->传输的速率主机->网络的速率】&#xff09;报文段的头部很小&#xff08;开销小&#xff09;UDP被用于 流媒…

数据结构系列-堆排序当中的T-TOK问题

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 之前我们讲到了堆排序的实现逻辑&#xff0c;那么接下来我们重点关注的就是其中的T-TOK问题 T-TOK说简单点&#xff0c;就是说&#xff0c;假如有10000个数据&#xff08;随机的…

bottle,Python轻量级的Web框架!

目录 前言 安装 特性 基本功能 1. 路由功能 2. 请求参数获取 3. 静态文件服务 4. 模板渲染 高级功能 1. 中间件 2. 插件 3. 异步处理 实际应用场景 1. 小型Web应用 2. RESTful API服务 3. Web界面与后端逻辑分离 4. Web服务的快速原型开发 总结 前言 大家好&#xff0c…

YOLOv9改进策略 | 添加注意力篇 | TripletAttention三重注意力机制(附代码+机制原理+添加教程)

一、本文介绍 本文给大家带来的改进是Triplet Attention三重注意力机制。这个机制&#xff0c;它通过三个不同的视角来分析输入的数据&#xff0c;就好比三个人从不同的角度来观察同一幅画&#xff0c;然后共同决定哪些部分最值得注意。三重注意力机制的主要思想是在网络中引入…