Redis学习笔记——万金油string为什么不好用了?

为什么string不好用了

首先string太大了

在Redis中,保存一个string需要使用64字节。如果要保存一个long型整数,原数据只有8字节,而却需要八倍的空间去存储它,这在保存大量数据时时非常不划算的。

为什么需要用的64字节的空间?

因为string不光有自身数据,还有一些“辅助”数据,比如自身的长度以及所占空间,这两个分别需要4字节,目前需要16字节。这些数据称为简单动态字符串(Simple Dynamic String,SDS)

在这里插入图片描述

而这之外还需要“包裹一层”RedisObject,由元数据和指向SDS。这时总共是32字节。

在这里插入图片描述
又因为Redis会使用一个全局哈希表保存所有键值对,哈希表的每一项是一个 dictEntry 的结构体,用来指向一个键值对。dictEntry 结构中有三个 8 字节的指针,分别指向 key、value 以及下一个 dictEntry,三个指针共 24 字节。

在这里插入图片描述
而使用jemalloc系统分配空间时,为了防止分配的空间不够,造成反复的申请空间,所以会选择比申请空间大的,离得最近的2的n次幂作为分配空间的大小。所以会分配32字节。

至此总共需要64字节。

用什么数据结构可以节省内存?

Redis 有一种底层数据结构,叫压缩列表(ziplist),这是一种非常节省内存的结构。

表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表长度、列表尾的偏移量,以及列表中的 entry 个数。压缩列表尾还有一个 zlend,表示列表结束。

压缩列表每一项有如下数据:

  • prev_len,表示前一个 entry 的长度。prev_len 有两种取值情况:1 字节或 5 字节。取值 1 字节时,表示上一个 entry 的长度小于 254 字节;
  • len:表示自身长度,4 字节;
  • encoding:表示编码方式,1 字节;
  • content:保存实际数据。

所以一次算下来需要14字节,系统分配16字节。

Redis 基于压缩列表实现了 List、Hash 和 Sorted Set 这样的集合类型,这样做的最大好处就是节省了 dictEntry 的开销。当你用 String 类型时,一个键值对就有一个 dictEntry,要用 32 字节空间。但采用集合类型时,一个 key 就对应一个集合的数据,能保存的数据多了很多,但也只用了一个 dictEntry,这样就节省了内存。

这个方案听起来很好,但还存在一个问题:在用集合类型保存键值对时,一个键对应了一个集合的数据,但是在我们的场景中,一个图片 ID 只对应一个图片的存储对象 ID,我们该怎么用集合类型呢?换句话说,在一个键对应一个值(也就是单值键值对)的情况下,我们该怎么用集合类型来保存这种单值键值对呢?

如何用集合类型保存单值的键值对?

在保存单值的键值对时,可以采用基于 Hash 类型的二级编码方法。这里说的二级编码,就是把一个单值的数据拆分成两部分,前一部分作为 Hash 集合的 key,后一部分作为 Hash 集合的 value,这样一来,我们就可以把单值数据保存到 Hash 集合中了。

以图片 ID 1101000060 和图片存储对象 ID 3302000080 为例,我们可以把图片 ID 的前 7 位(1101000)作为 Hash 类型的键,把图片 ID 的最后 3 位(060)和图片存储对象 ID 分别作为 Hash 类型值中的 key 和 value。

不过,为什么二级编码一定要把图片 ID 的前 7 位作为 Hash 类型的键,把最后 3 位作为 Hash 类型值中的 key 吗?其实,二级编码方法中采用的 ID 长度是有讲究的

Redis Hash 类型的两种底层实现结构,分别是压缩列表和哈希表。

那么,Hash 类型底层结构什么时候使用压缩列表,什么时候使用哈希表呢?其实,Hash 类型设置了用压缩列表保存数据时的两个阈值,一旦超过了阈值,Hash 类型就会用哈希表来保存数据了。

一个是单个元素的最大长度,另一个是用压缩列表保存时哈希集合中的最大元素个数。

因为哈希表在压缩内存方面没有压缩列表高效,所以为了能充分使用压缩列表的精简内存布局,我们一般要控制保存在 Hash 集合中的元素个数。所以,在刚才的二级编码中,我们只用图片 ID 最后 3 位作为 Hash 集合的 key,也就保证了 Hash 集合的元素个数不超过 1000,同时,我们把 hash-max-ziplist-entries 设置为 1000,这样一来,Hash 集合就可以一直使用压缩列表来节省内存空间了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值