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

Redis系列之底层数据结构ZipList

Redis系列之底层数据结构ZipList

实验环境

  • Redis 6.0

什么是Ziplist?

Ziplist,压缩列表,这种数据结构会根据存入数据的类型和大小,分配大小不同的空间,所以是为了节省内存而采用的。因为这种数据结构是一种完整连续的数据单元,所以一旦发生数据改变,会产生连锁更新,严重影响访问性能,所以这种数据结构只适应于数据量比较小的情况。

ZipList可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。

ZipList数据结构

在Redis的源码找到ziplist.c,链接:https://github.com/redis/redis/blob/6.0/src/ziplist.c

/* The ziplist is a specially encoded dually linked list that is designed
 * to be very memory efficient. It stores both strings and integer values,
 * where integers are encoded as actual integers instead of a series of
 * characters. It allows push and pop operations on either side of the list
 * in O(1) time. However, because every operation requires a reallocation of
 * the memory used by the ziplist, the actual complexity is related to the
 * amount of memory used by the ziplist.
 *
 * ----------------------------------------------------------------------------
 *
 * ZIPLIST OVERALL LAYOUT
 * ======================
 *
 * The general layout of the ziplist is as follows:
 *
 * <zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend> // ziplist的整体布局
 *
 * 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.
 *
 * 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里面的结构
 * ...
 */

根据源码里的说明,画出ziplist的数据结构:
在这里插入图片描述

  • zlbytes:字段的类型是unit32_t,这个字段存储的是整个ziplist所占用的内存字节数
  • zltail:字段的类型是unit32_t,指的是ziplist中最后一个entry的偏移量,用于快速定义最后一个entry,可以快速完成pop等操作
  • zllen:字段的类型是unit16_t,指的是整个ziplist中entry的数量
  • zlend:是一个终止字节,值为全F,即0xff

entry数据结构

从上面的介绍,还知道entry也是很重要的数据结构,看Redis源码里的介绍,entry一般分为如下圈出的两种结构
在这里插入图片描述

  • 第一种结构,<prevlen> <encoding> <entry-data>,这种是常规的结构
    • prevlen:前一个entry的大小
    • encoding:不同的情况encoding的值不同,encoding用于表示当前的entry的类型和长度
    • entry-data:用于存储entry的数据
  • 第二种结构,<prevlen><encoding>,当entry存储的是int类型的数据时,encodingentry-data会合并在encoding中表示,此时数据结构为<prevlen><encoding>

在Redis中,存储数据时会尝试将string类型数据转为int类型数据,以节省内存空间

  • prevlen编码
    当前一个元素长度小于254的时候,prevlen长度为1个字节,值即为前一个entry的长度;如果元素长度大于等于254的时候,prevlen用5个字节表示,第一字节设置为254,后面4个字节存储一个小端的无符号整型,用来表示前一个entry的长度
<prevlen from 0 to 253> <encoding> <entry> // 元素长度小于254
0xFE <4 bytes unsigned little endian prevlen> <encoding> <entry> // 元素长度大于254

源码里的原文:
在这里插入图片描述

  • encoding编码

encoding的长度和值根据存储的数据类型和长度而定,前两位表示数据类型,比如int类型,用"11"表示,其它的表示string类型

源码里的注释给出的例子,分别举例表示encoding存储String类型数据和int类型数据的场景
在这里插入图片描述

  • entry-data
    entry-data存储entry的数据,存储的数据为字符串类型时才会有,为int类型时,encodingentry-data会合并

什么情况使用ZipList?

上面说了,ziplist数据是连续的,是一个完整的内存空间,所以如果发生数据变更,会产生连锁更新,影响访问性能,所以只适应于数据量比较小的情况。

在Redis中有两种数据结构,hashessorted Sets在某些情况会使用ZipListhashes只有小数据量的时候才会用到ziplist,当hash对象符合如下两个条件的时候,使用ziplist

  • hash对象保存的键值对数量小于512个;
  • 所有的键值对的键和值的字符长度都小于64byte

redis.conf配置

hash-max-ziplist-value 64  // ziplist中最大能存放的值长度
hash-max-ziplist-entries 512 // ziplist中最多能存放的entry数量

sorted Sets在某些情况使用zipList,如果元素数量小于128个,或者任一个member长度小于64字节,如果两个条件都超过,即大于等于,使用Skiplist+dict存储

redis.conf配置:

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

Ziplist为什么省内存?

ZipList在设计的时候就尽量让每个元素按照实际大小存储,所以在entry里增加encoding字段,这个字段表示entry的类型和长度,redis针对不同的encoding来细化存储大小,所以比起普通的List,ziplist会更省内存,普通的list每个元素占用的内存空间大小取决于最大元素所占用的内存空间。

按照这种设计方式,Ziplist无疑会更省内存,但是也有一个问题,就是遍历比起普通的list会更麻烦,所以新增了prelen字段,这个字段记录上一个元素的length


http://www.kler.cn/a/397892.html

相关文章:

  • Android Mobile Network Settings | APN 菜单加载异常
  • EWM 打印
  • 222. 完全二叉树的节点个数【 力扣(LeetCode) 】
  • 外网访问 WebDav 服务
  • IDEA2024:右下角显示内存
  • git配置用户信息
  • 蓝桥杯每日真题 - 第15天
  • 24下软考高级【系统架构设计师】考试难度分析
  • Python学习27天
  • OpenGL ES 文字渲染进阶--渲染中文字体
  • NOIP2007T1 统计数字
  • Android 配置默认输入法
  • Scala中的迭代器
  • 如何找出爬取网站的来源IP呢?
  • 对接阿里云实人认证
  • UG Motion学习笔记
  • 【AI图像生成网站Golang】JWT认证与令牌桶算法
  • 在 Linux 系统上部署 Oracle 数据库涉及多个步骤
  • AI技术如何助力电商平台提升销售效率与用户体验?——创新应用、挑战与未来发展趋势
  • 【代码随想录回溯算法|子集问题】
  • 排序算法(基础)大全
  • 网络工程实验四:NAT的配置
  • 【MongoDB】MongoDB的核心-索引原理及索引优化、及查询聚合优化实战案例(超详细)
  • 【基于轻量型架构的WEB开发】课程 13.2.4 拦截器 Java EE企业级应用开发教程 Spring+SpringMVC+MyBatis
  • 机器学习:XGBoost模型(升级版)——高效且强大的树形模型
  • 安全见闻4