Redis压缩列表

此篇文章是主要介绍Redis在数据存储方面的其中一种方式,压缩列表。本文会介绍1. 压缩列表(ziplist)的使用场景 2.如何达到节约内存的效果?3.压缩列表的存储格式 4. 连锁更新的问题  5. conf文件配置。在实践上的操作主要是对conf配置文件进行配置,具体上没有确切的一个值,更多是经验值。也有的项目会直接使用原本的默认值。此篇对于更好地理解一个数据库底层的存储逻辑会有一点帮助。修学储能,既要博,也要渊。希望这篇文章对同样也是在学习Redis的各位同伴有点用。

一、压缩列表(ziplist)的使用场景:

Redis为了优化数据存储,节约内存,在列表、字典(哈希键)和有序集合的底层实现了使用压缩列表这一优化方案。

例如,假如一个哈希键里面存储的字符串比较短,那么Redis就会将它用压缩列表的格式去存储,即转换为字节数组存储。而一个哈希键内部存储的整数值比较小,同样也会把它存储为压缩列表的一个节点。同理,列表键的对小数据的存储跟哈希键的操作类似。

如此说来,压缩列表并不是开发者可以直接调用的Redis中的一种存储数据结构,而是Redis中为优化数据存储而在底层做的一项努力。理解好这点还是比较重要的。

二、如何达到节约内存的效果?

压缩列表是一种序列化的数据结构,这种数据结构的功能是将一系列数据与其编码信息存储在一块连续的内存区域,这块内存物理上是连续的。但逻辑上被分为多个组成部分,即节点。目的是为了在一定可控的时间复杂度条件下尽可能的减少不必要的内存开销,从而达到节省内存的效果。需要理解是怎么达到节约内存作用的,还需要去了解压缩列表的存储格式。

三、压缩列表的存储格式:

压缩列表(ziplist)是Redis列表键、哈希键和有序集合键的底层实现之一,其实质是一种序列化的数据存储结构。有别于普通情况下,Redis用双端链表表示列表,使用散列表表示哈希键,用散列表+跳跃表表示有序集合。当一个列表或者哈希字典/有序集合只包含很少内容,并且每一个列表项或者哈希项/有序集合项如果是小整数,或者比较短的字符串。那么Redis就会用压缩列表来做底层的实现。

 

压缩列表由一系列经Redis特殊编码的连续内存块组成,每一个内存块称为一个节点(entry),而一个压缩列表可以包含很多个节点。每个节点存储的数据格式可以是字节数组(中文字符串等都会转换为字节数组)或者整数值。

字节数组的长度可以是以下的其中一种:

1. 长度小于等于63字节(2的6次方)

2. 长度小于等于16383字节(2的14次方)

3. 长度小于等于4294967295字节(2的32次方)

整数值可能是以下六种中的其中一种:

1. 4位长,介于0-12之间的无符号整数

2. 1字节长的有符号整数

3. 3字节长的有符号整数

4. int16_t类型整数

5. int32_类型整数

6. int64_t类型整数

普通存储格式下和压缩列表存储格式下的不同点:

列表存储结构典型的为双端链表,每一个值都是用一个节点来表示,每个节点都会有指向前一个节点和后一个节点的指针,以及指向节点包含的字符串值的指针。而字符串值又分为3个部分存储,第一部分存储字符串长度,第二部分存储字符串值中剩余可用的字节量,第三部分存储的则是字符串数据本身。所以一个节点往往都需要存储3个指针、2个记录字符串信息的整数、字符串本省和一个额外的字节。总体上额外的开销是很大的(21字节)。

压缩列表节点的格式:

每一个节点都有previous_entry_length,encoding,content三个部分组成,在遍历压缩列表的时候是从后往前遍历的。

1. previous_entry_length记录了前一个节点的长度,只要用当前指针减去这个值就可以达到前一个节点的起始地址。

2. encoding记录了节点content属性所保存数据的类型和长度

3. content记录了一个节点的值

显然压缩列表这种方式节约了不少存储空间。但同时也会引发下面的问题。

四、连锁更新的问题:

一般而言如果前一个节点的整体长度小于254字节,previous_entry_length属性只需要1个字节的空间来保存这个长度值。而当前一个节点大于254字节的时候,previous_entry_length属性要用5个字节长的空间来记录长度值。

当长度为254字节左右的节点前插入一个新的节点的时候,需要增加previous_entry_length来记录这个节点到新节点的偏移量。这个时候,这个节点的长度肯定就大于254字节了。所以这个节点的后一个节点就不能只用一个字节的previous_entry_length来记录这个节点的信息了,而是需要5个字节来记录。如果连续多个节点的长度都为254字节左右,在其中的某一个节点前/后发生节点的插入和删除(删除的推理与插入相反,原本用5字节记录前一节点的可能变为1字节),都可能引发连锁的更新,显然,这样对系统地运行效率是很不利的。不过,在实际应用中这种情况还是比较少发生的。

而双端链表在节点的更新、增加和删除上显得就会“轻松”很多了。 因为每一个节点存储的信息都是相对独立的。

实践意义:

要预估一个节点大概占据多少字节的存储空间,适当地调整字段的存储格式而不要使存储的字段值占据存储空间落在254字节(除去encoding属性和previous_entry_length属性)左右。

Redis中查看字符串和哈希键值的长度相关命令:

1. 查询字符串键对应的值长度

命令:

Strlen

例如:

127.0.0.1:6379> strlen m_name

(integer) 8

2. 查询哈希键某一个域长度

命令:

Hstrlen

例如:

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

五、Conf文件配置:

通过修改配置文件,可以控制是否使用压缩列表存储相关键的最大元素个数和最大元素的大小

Conf文件中的配置:

1.

[] -max-ziplist-entries : 表示对于键的最大元素个数,即一个键中在该指定值下的数量的节点个数都会用压缩列表来储存

[] -max-ziplist-value :表示压缩列表中每个节点的最大体积是多少字节

实际使用中,一个列表键/哈希键的某一个元素往往存储着比较大的信息量,会大于64字节,所以配置时很有可能会比64大,同时考虑到实际存储数据的容量大小以及上面谈到的previous_entry_length的大小问题,对[] -max-ziplist-value进行合理的配置。

配置文件内容:

############## ADVANCED CONFIG ##########################
哈希键
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64

有序集合键
# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

列表键,比较特殊,直接使用制定大小kb字节数表示(有些conf文件的列表键与hash键的表达式没太大区别)
# Lists are also encoded in a special way to save a lot of space.
# The number of entries allowed per internal list node can be specified
# as a fixed maximum size or a maximum number of elements.
# For a fixed maximum size, use -5 through -1, meaning:
# -5: max size: 64 Kb  <-- not recommended for normal workloads
# -4: max size: 32 Kb  <-- not recommended
# -3: max size: 16 Kb  <-- probably not recommended
# -2: max size: 8 Kb   <-- good
# -1: max size: 4 Kb   <-- good
# Positive numbers mean store up to _exactly_ that number of elements
# per list node.
# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),
# but if your use case is unique, adjust the settings as necessary.
list-max-ziplist-size -2

案例:

修改配置前使用默认配置:

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

127.0.0.1:6379> object encoding good_list

"hashtable"

修改配置:

hash-max-ziplist-entries 512

hash-max-ziplist-value 254

注意:修改配置后需要重启服务器

127.0.0.1:6379> hstrlen good_list good_list1

(integer) 226

127.0.0.1:6379> object encoding good_list

"ziplist"

可以看到存储方式已将变为ziplist

较官方的压力测试和指导建议:

当一个压缩列表的元素数量上升到几千(实际使用可能远小于这个值)的时候,压缩列表的性能可能会下降,因为Redis在操作这种结构的时候,编解码会出现一定的压力。

压缩列表的长度限制在500-2000之内,每个元素体积限制在128字节或以下,压缩列表的的性能都会处于合理范围之内。

参考资料:

《redis设计与实现》

原文地址:https://www.cnblogs.com/thomson-fred/p/10354357.html

时间: 2024-11-02 20:39:07

Redis压缩列表的相关文章

Redis压缩列表原理与应用分析

摘要 Redis是一款著名的key-value内存数据库软件,同时也是一款卓越的数据结构服务软件.它支持字符串.列表.哈希表.集合.有序集合五种数据结构类型,同时每种数据结构类型针对不同的应用场景又支持不同的编码方式.这篇文章主要介绍压缩列表编码,在理解压缩列表编码原理的基础上介绍Redis对压缩列表的应用,最后再对Redis压缩列表应用进行分析. 摘要 Redis是一款著名的key-value内存数据库软件,同时也是一款卓越的数据结构服务软件.它支持字符串.列表.哈希表.集合.有序集合五种数据

学习笔记-Redis设计与实现-压缩列表

压缩列表(ziplist)是列表键和哈希键的底层实现之一. 7.1 压缩列表的构成 压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构.一个压缩列表可以包含任意多个节点(entry),每个节点可以保存数组或者一个整数值. 7.2 压缩列表节点的构成 每个压缩列表节点可以保存一个字节数组或者一个整数值. 每个压缩列表节点都由previous_entry_length.encoding.content三个部分组成. 7.2.1 pre

Redis数据结构之压缩列表

压缩列表是Redis为了节约内存而开发的,由一系列特殊编码的连续内存块组成的顺序型数据结构.一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或者一个整数值. 一.压缩列表结构1. 压缩列表结构: 参数说明:zlbytes:记录整个压缩列表占用的内存字节数.zltail:记录压缩列表表尾节点距离压缩列表起始地址有多少字节.zllen:记录了压缩列表包含的节点数量.entryN:压缩列表的节点,节点长度由节点保存的内容决定.zlend:特殊值0xFF(十进制255),用于标记压缩列表的

redis 底层数据结构 压缩列表 ziplist

当一个哈希键只包含少量键值对,并且每个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做哈希键的底层实现. 压缩列表是Redis为了节约内存而开发的是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或者一个整数值 ziplist 数据结构 压缩列表节点的构成 每个压缩列表节点可以保存一个字节数组或者一个整数值,其中字节数组可以是以下三种长度的其中一种 长度小于等于63字节的字节数组 长度小

Redis实现之压缩列表

压缩列表 压缩列表(ziplist)是列表键和哈希键的底层实现之一,当一个列表键只包含少量列表项,并且每个列表项要嘛是整数值,要嘛是比较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现.例如,执行以下命令将创建一个压缩列表键的底层实现 127.0.0.1:6379> RPUSH lst 1 3 5 10086 "hello" "world" (integer) 6 127.0.0.1:6379> OBJECT ENCODING lst &q

Redis数据结构之压缩列表-ziplist

为了节约内存,在zset和hash容器对象元素个数较少时,Redis会采用压缩列表(ziplist)进行存储. 压缩列表是一块连续的内存空间,元素之间紧挨着存储,不存在冗余 一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值 结构 // 压缩列表 struct ziplist<T> { int32 zlbytes; // 压缩列表占用的内存字节数 int32 zltail_offset; // 记录表尾节点距离起始地址有多少个字节,用于快速定位最后一个元

Redis设计与实现 - chapter7 压缩列表

Chapter7 压缩列表 列表键和哈希键的底层实现之一(列表键只包含少量元素,且元素为小整数或较短字符串:而哈希键之包含少量键值对,且每个键值对的key和value都是小整数或较短字符串). 为了节约内存. 压缩列表的组成 一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构,包含多个节点entry,每个entry保存一个字节数组或一个整数. 内存组织: 具体含义: 压缩列表节点的组成 每个节点保存一个字节数组或者一个整数值,由 previous_entry_length .

Redis2.6源代码走读第007课:压缩列表02

身体被掏空了一星期, 前天终于挣扎着继续做这个代码走读 不得不说, 压缩列表的实现复杂程度还是超出了我的预计 破天荒的第一次, 我必须手动上注释, 才能防止自己迷失在代码里面. 今天还没有录制视频, 最近一直在做公司的事, 时间也比较紧, 所以今天只是把我经过注释的压缩列表部分的代码贴出来, 同时给出一个阅读建议 在学习压缩列表的过程中, 我也参考了黄健宏先生对Redis2.6源代码的注释, 发现了黄先生注释中的一个错误. 如下: unsigned char *ziplistFind(unsig

第七课——简单动态字符串、链表、字典、压缩列表

第七课时作业 静哥 by 2016.4.5~2016.4.10   [作业描述] 1.解释redis数据库是怎么扩容的? 2.用几句话描述sds结构和压缩列表 [作业-1:解释redis数据库是怎么扩容的] Redis数据库是使用字典作为底层实现的,对数据库的增删改查操作也是构建在对字典的操作之上.因此,redis数据库的扩容本质上就是字典的扩容. Redis数据库是使用字典作为底层实现的:而字典使用哈希表作为底层实现:哈希表则可以由多个哈希表节点构成:哈希表节点里保存字典中的一个键值对. 对哈