4、认识redis的set集合

介绍

在 Java 里面,HashSet 底层是用 HashMap 实现的。在 Redis 里面也是类似的,Redis 里面的 Hash 底层结构是 dict,Set 底层的结构也是 dict。但是,在元素都是整数值的时候,Set 可以用一种更省空间的方式来存数据,这种省空间的方式就是这一节要说的 intset。

一个 Set 要用 intset 作为底层存储的话,需要满足两个条件:

  • 元素都是整数类型
  • 这个 Set 里面的元素个数,要少于 set-max-intset-entries 配置指定的这个值,这个值默认是 512

一旦这个 Set 集合不满足这两个条件,就会切换成 dict 作为底层存储。Redis 之所以使用 intset 结构来进行优化,主要是为了减少内存碎片,提高查询效率,这也体现了 Redis 在空间占用和耗时等方面的折中和思考

关于dict, 可以参考这篇文章 认识redis的hash

intset 结构体

从名字就可以看出,intset 结构体是用来存储整数类型的集合,不仅如此,intset 中存储的整数还是有序的,这样我们就可以非常方便地使用二分查找来查找一个元素。下面来看 intset 结构体的定义:

typedef struct intset {
    uint32_t encoding; // 编码类型
    uint32_t length; // contents数组的长度
    int8_t contents[]; // 柔性数组,不使用时不占用空间
} intset;
  • encoding: 编码格式,表示 intset 中存储的每个元素需要用几个字节来存储。其可选值有如下三个:
    • INTSET_ENC_INT16:值为 2,表示所有元素值都处于 [INT16_MIN, INT16_MAX] 范围内,那么在 contents 数组中每 2 个字节表示一个整数元素。
    • INTSET_ENC_INT32:值为 4,表示有元素的值处于 (INT16_MAX, INT32_MAX] 或是 [INT32_MIN, INT16_MIN) 范围内,那么在 contents 数组中每 4 个字节表示一个元素
    • INTSET_ENC_INT64:值为 8,表示有元素的值处于 (INT32_MAX, INT64_MAX] 或是 [INT64_MIN, INT32_MIN) 范围内,那么在 contents 数组中每 8 个字节表示一个元素。
  • length 字段:表示 intset 中的元素个数
  • contents 字段:用来存储 intset 中元素的数组,这是个柔性数组,不使用时不会占用空间

从 intset 结构体的定义可以看出,它与前文介绍的 ziplist 类似,也是通过一块连续的内存空间实现的,如下图所示,其中 encoding 和 length 两部分构成了 intset 的头,总共占 8 字节。
在这里插入图片描述

添加数据与扩容

  1. 计算插入值的编码值, 判断是不是在encoding范围内, 如果小于intset的encoding编码值, 数据会按照当前编码方式存储, 并占据当前编码大小的字节数, Redis 不会降级或压缩 intset 中的编码类型
  2. 当插入的值的编码值大于当前intset的encoding范围, 会触发升级
  • 扩容时,将所有元素从当前编码类型转换为更大的编码类型; 16位 → 32位, 32位 → 64位
  • 例如, 集合内存储 int16 类型的整数,范围为:-32768 ~ 32767, 当插入超过范围的数,例如 40000,会触发扩容,将整个集合升级为 int32 类型; 若再插入超过 int32 范围的数,例如 10^10,会再扩容为 int64 类型
  • 数据重新排列,迁移到新的内存空间

查找数据

  1. 计算目标值的编码值, 判断是否在encoding范围内, 不存在直接查找失败
  2. 编码值匹配成功后, 使用二分法查找

总结

  1. 当set集合中的元素满足以下条件时会使用intset作为存储结构, 否则使用dict作为数据存储结构
  • 元素都是整数类型
  • 这个 Set 里面的元素个数,要少于 set-max-intset-entries 配置指定的这个值,这个值默认是 512
  1. intset根据不同的编码类型, 使用不同字节存储整数
  • INTSET_ENC_INT16(2位): -215 ~ 215-1
  • INTSET_ENC_INT32(4位): -232 ~ 232-1
  • INTSET_ENC_INT64(8位): -264 ~ 264-1
  1. intset中的数据存储有序

个人公众号: 行云代码

参考文章

说透 Redis 7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

uncleqiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值