Redis 学习笔记(篇四):整数集合和压缩列表
整数集合
Redis 中当一个集合(set)中只包含整数,并且元素不多时,底层使用整数集合实现,否则使用字典实现。
那么:
- 为什么会出现整数集合呢?都使用字典存储不行吗?
- 整数集合在 Redis 中的结构是怎样的呢?
- 引入整数集合之后,会不会出现什么弊端?Redis 又是如何去解决的呢?
为什么会出现整数集合呢?都使用字典存储不行吗?
说起无序集合(set),很自然的就想起哈希表,而哈希表表现也很好,提供了查询为 O(1) 的时间复杂度。但任何事物有优点,就必然会伴随着一些缺点,哈希表的缺点就是使用的储存空间大,其实哈希表本身就是空间换取时间的一种方式。
Redis 作为一个缓存,考虑到内存的使用,所以出现了整数集合这一数据结构。然而整数集合虽然相比哈希表很节约内存,但它也是牺牲了速度作为代价的。所以 Redis 中也只是在数据量少的条件下才会去使用整数集合代替哈希表。
整数集合在 Redis 中的结构是怎样的呢?
Redis 中的整数集合由 intset.h/intset 表示,具体结构如下:
typedef struct intset {
// 编码方式
uint32_t encoding;
// 集合包含的元素数量
uint32_t length;
// 保存元素的数组
int8_t contents[];
} intset;
length属性表示整数集合包含的元素数量,即是contents数组的长度。
contents 数组是整个整数集合最核心的部分,元素就存储在这个数组中,各个元素从小到大有序排列,并且没有重复元素。虽然 contents 数组是声明成int8_t的类型,但是存储元素的真正类型并不是 int8_t 而是由 encoding 属性来表示 contents 数组真正的类型。比如:
- 如果 encoding 属性的值为 INTSET_ENC_NT16,那么 contents 就是一个 int16_t 类型的数组,数组里的每个项都是一个 int16_t 类型的整数值(最小值为 -32768,最大值为 32767)。
- 如果 encoding 属性的值为 INTSET_ENC_NT32,那么 contents 就是一个 int32_t 类型的数组,数组里的每个项都是一个 int32_t 类型的整数值(最小值为 -2^31,最大值为 2^31-1)。
引入整数集合之后,会不会出现什么弊端?
当我们向集合中插入元素时,Redis 并没有让我们指定插入的数值是几个字节的,那么如果我们先插入了 int16_t 的元素,然后插入了一个 int32_t 的元素,那么这时候原来的 contents 存不了新插入的值,这个时候该怎么做呢? 这也就是 Redis 引入整数集合之后所要解决的问题。
Redis 为了解决这个问题,于是引入了升级。
升级
每当我们要将一个新元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级,然后才能将新元素添加到整数集合里面。具体步骤如下:
- 根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间。
- 将底层数组现有的所有元素都转换成与新元素相同的类型,并将类型转换后的元素
- 将新元素添加到底层数组(contents)里面。
升级的时间复杂度是 O(n),又每次向整数集合添加新元素都可能引发升级,所以整数集合添加新元素的时间复杂度是 O(n)。
而为整数集合引入升级之后,主要带来了两点好处:
第一:提升了程序的灵活性。
第二:节约内存。
看到这里,可能有的人会想,有了升级,那么有没有降级呢?很遗憾,Redis 中的整数集合没有降级,也就是说只能扩容,不能缩容。
压缩列表
本篇只是简单介绍一下压缩列表,所以暂不深入讲解,感兴趣的可以自行查阅其他资料。
Redis 在什么情况下会使用压缩列表作为底层实现呢?
- 列表只包含少量元素,并且每个列表项要么是小整数值,要么是长度较短的字符串。
- 哈希键中只包含少量键值对,并且每个键值对的键和值要么是小整数值,要么是长度较短的字符串。
其实看到压缩二字,就能联想到节约内存。所以本篇介绍的整数集合和压缩列表都是为了节约内存而存在的。那么,压缩列表的大致结构是什么?
压缩列表的大致结构
压缩列表是由一系列特殊编码的连续内存块组成的顺序型数据结构。一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组(字符串)或者一个整数值。
它的各个组成部分和说明如下(出自《Redis设计与实现第二版》第7章:压缩列表):

压缩列表更像是一种存储方式,和 Java 字节码中常量池的存储比较类似。感兴趣的可以去查一下。
压缩列表的节点主要由 previous_entry_length、encoding、content 三部分组成。如下图(出自《Redis设计与实现第二版》第7章:压缩列表):

- previous_entry_length 表示压缩列表中前一个节点的长度,单位为字节。
- encoding 记录了节点的 content 属性所保存数据的类型及长度。
- content 则负责保存节点的值。可以使一个字节数组(字符串)或者整数。
Redis 学习笔记(篇四):整数集合和压缩列表的更多相关文章
- Redis学习笔记(四)集合进阶
1.组合与关联多个集合 差集: SDIFF key1 [key2...](返回存在于key1但不存在其他集合中的元素) SDIFFSTORE destination key1 [key2...](将存 ...
- Redis底层探秘(四):整数集合及压缩列表
整数集合 整数集合(intset)是集合键的底层实现之一,当一个集合只包含 整数值元素,并且这个集合的元素数量不多时,Redis就会使用郑书记和作为集合键的底层实现. 整数集合的实现 整数集合是red ...
- Redis数据结构—整数集合与压缩列表
目录 Redis数据结构-整数集合与压缩列表 整数集合的实现 整数集合的升级 整数集合不支持降级 压缩列表的构成 压缩列表节点的构成 小结 Redis数据结构-整数集合与压缩列表 大家好,我是白泽.今 ...
- redis 笔记01 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表
文中内容摘自<redis设计与实现> 简单动态字符串 1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态 ...
- 【转】Redis学习笔记(四)如何用Redis实现分布式锁(1)—— 单机版
原文地址:http://bridgeforyou.cn/2018/09/01/Redis-Dsitributed-Lock-1/ 为什么要使用分布式锁 这个问题,可以分为两个问题来回答: 为什么要使用 ...
- Redis学习笔记(四)——数据结构之List
一.介绍 Redis列表(List)是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(left)或者尾部(right),一个列表最多可以包含232-1个元素(4294967295, ...
- Redis 学习笔记(四)RDB 和 AOF 持久化机制
一.Redis 持久化简介 Redis 的持久化功能是区别于 Memcached 显著特性,数据持久化可以保证系统在发生宕机和重启后数据不会丢失,对于 redis 这种存储在内存中的数据库显得尤为重要 ...
- Redis学习笔记(四)-数据类型之list类型
redis的list类型其实就是一个每个子元素都是string类型的双向链表.所以[lr]push和[lr]pop命令的算法时间复杂度都是O(1).另外list会记录链表的长度.所以llen操作也是O ...
- Redis学习笔记(四) 基本命令:String操作
原文链接:http://doc.redisfans.com/string/index.html append key value 将指定的值追加到key末尾,若key不存在,则创建并赋值,返回追加后的 ...
随机推荐
- 跟我学ASP.NET MVC之十一:URL路由
摘要: 在MVC框架之前,ASP.NET假定在请求的URLs和服务器硬盘文件之间有直接的关系.服务器的职责是接收浏览器请求,从相应的文件发送输出. 这种方法只能工作于Web表单,每一个ASPX页面既是 ...
- 编写可移植C/C++程序的要点(12条)
1.分层设计,隔离平台相关的代码.就像可测试性一样,可移植性也要从设计抓起.一般来说,最上层和最下层都不具有良好的可移植性.最上层是GUI,大多数GUI都不是跨平台的,如Win32 SDK和MFC.最 ...
- 入骨三分的“我们是谁”IT行业版
这组漫画用简单的台词.粗犷的线条,把很多人心中对甲方(客户)的不满彻底地发泄了一通,并且出现了很多变种版本,引发了传播热潮. http://news.sina.com.cn/c/nd/2017-08- ...
- Webx框架:Pipeline基本介绍
Pipeline. 它是管道的含义.一个管道阀门可以安装非常多.有许多可能的分支.它是用来控制页处理.它需要在被定义pipeline.xml文件.该文件是为每个阀的标签.该文件可以放一些简单的控制语句 ...
- maven私服nexus安装
maven私服nexus安装 1.nexus特性 1.1.nexus私服实际上是一个javaEE的web 系统 1.2.作用:用来管理一个公司所有的jar包,实现项目jar包的版本统一 1.3.jar ...
- WPF中样式和行为和触发器
原文:WPF中样式和行为和触发器 样式简介:样式(style)是组织和重用格式化选项的重要工具,不是使用重复的标记填充XAML,以便设置外边距.内边距.颜色以及字体等细节.而是创建一系列封装所有这些细 ...
- php 二维数组key初始化从0开始
这个是一个二维数组 array(2) { [1]=> array(2) { ["sourcesid"]=> int(1) ["addusernum" ...
- ARM中 __IO的作用解析
__IO在头文件中预定义 #define __IO volatile volatile 影响编译器编译的结果, 指出:volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要 ...
- Sublime text追踪函数插件:ctags[转载]
一.下载(择其一即可): 1)http://ctags.sourceforge.net/ 2)http://prdownloads.sourceforge.net/ctags/ 解压后单独取出ctag ...
- 使用BGP的虚拟下一跳实现IGP的路由负载
网络拓扑: XRV1 ============================================================== !hostname XRV1! interface ...