Redis压缩列表的示例分析

49次阅读
没有评论

共计 4564 个字符,预计需要花费 12 分钟才能阅读完成。

自动写代码机器人,免费开通

这篇文章主要介绍了 Redis 压缩列表的示例分析,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获。下面让丸趣 TV 小编带着大家一起了解一下。

此篇文章是主要介绍 Redis 在数据存储方面的其中一种方式,压缩列表。

本文会介绍

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

2. 如何达到节约内存的效果?

3. 压缩列表的存储格式

4. 连锁更新的问题  

5. conf 文件配置。

在实践上的操作主要是对 conf 配置文件进行配置,具体上没有确切的一个值,更多是经验值。也有的项目会直接使用原本的默认值。此篇对于更好地理解一个数据库底层的存储逻辑会有一点帮助。修学储能,既要博,也要渊。希望这篇文章对同样也是在学习 Redis 的各位同伴有点用。(推荐教程: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 字节)。

压缩列表节点的格式:

Redis 压缩列表的示例分析

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

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

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

Redis 压缩列表的示例分析

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 字节或以下,压缩列表的的性能都会处于合理范围之内。

感谢你能够认真阅读完这篇文章,希望丸趣 TV 小编分享 Redis 压缩列表的示例分析内容对大家有帮助,同时也希望大家多多支持丸趣 TV,关注丸趣 TV 行业资讯频道,遇到问题就找丸趣 TV,详细的解决方法等着你来学习!

向 AI 问一下细节

丸趣 TV 网 – 提供最优质的资源集合!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-18发表,共计4564字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)