《Redis设计与实现》读书笔记(九) ——Redis集合和有序集合实现原理
《Redis设计与实现》读书笔记(九) ——Redis集合和有序集合实现原理
(原创内容,转载请注明来源,谢谢)
一、集合
集合的编码方式有intset和hashtable两种。
1、intset
intset是整数集合,集合使用此方式时,集合内的所有对象都保存在整数集合中。如下图所示:
2、hashtable
hashtable是字典,集合使用此方式时,集合内的所有对象都保存在字典的键中,值设置成null。每个对象保存在一个键中。
如下图所示:
3、编码实现条件
由于整数集合的效率比字典高,但是整数集合有一定的要求,如下:
1)集合内所有的元素必须是整数。
2)集合内元素个数不超过512个,512个这个数字是通过redis配置文件中的set-max-intset-entries属性进行配置的,默认是512个。
不满足以上两个任意条件的集合,则采用hashtable进行编码。
原先采用intset的集合,操作期间加入非整数或者元素个数超过512个,则redis会将其转换为hashtable编码方式。
4、集合命令实现
二、有序集合
有序集合的编码有ziplist和skiplist两种。
1、ziplist
ziplist是压缩列表,有序集合的每个集合元素使用两个连续的节点保存,前者保存节点具体内容,后者保存节点的score。
在压缩列表内,按照分数从小到大进行排序,分值较小的靠近表头,分值大的靠近表尾。
总体结构如下图所示:
压缩列表内部如下图所示:
2、skiplist
skiplist是跳跃表,redis中该结构专门为有序集合设计的,其他数据类型没有使用到该数据结构。
有序集合使用skiplist时,同时使用到字典。结构如下:
typedef structzset{
zskiplist *zsl;
dict *dict;
}zset;
总结构图如下:
1)跳跃表zsl
有序集合中,zsl按照分值从小到大保存集合所有元素,每个跳跃表节点都保存一个集合的元素:跳跃表节点的object属性保存了有序集合的成员,而score属性保存了有序集合的score。
通过zsl,可以对有序集合进行一些范围操作,包括zrank、zrange等命令就是基于跳跃表的api实现。
2)字典dict
除此之外,dict为有序集合创建了一个从成员到分值的映射,字典里面每个键值对都保存一个集合元素,键保存有序集合的成员,值保存有序集合的score。
通过dict,可以用O(1)的时间复杂度,通过成员找到分值。zscore和其他很多有序集合命令,都是通过集合的api实现。
内部编码结构如下图:
上图中值和分数写了两遍,是为了便于展示。实际上值和分数在skiplist和hashtable都是共享的,通过指针指向,而不是两个值。
3、有序集合skiplist+hashtable编码综述
有序集合每个成员是字符串对象,而分值是浮点数。
虽然有序集合同时使用了跳跃表和字典,但是这两个结构会通过指针的方式,共享有序集合的成员和分值,因此并不会浪费太多的内存空间。
虽然skiplist和hashtable都可以表示有序集合,但是结合在一起使用效率更高。hashtable的特性使得通过成员查找分值的速度极快,O(1);skiplist的特性使得有序集合的成员可以按照顺序排列,在执行范围型操作(如zrange、zrank等)时速度更快。
4、编码使用条件
当元素较少、长度较短时,使用ziplist效率显然更高,而且结构更简单。但是当元素太多、长度太长,使用ziplist的效率就不够高。使用ziplist,需要同时满足以下条件:
1)有序集合元素个数小于128个,通过配置文件的zset-max-ziplist-entries属性配置,默认是128个。
2)有序集合中的所有元素成员长度都小于64字节,通过配置文件的zset-max-ziplist-value属性配置,默认是64字节。
上述任一条件不满足,就会采用skiplist+hashtable的方式对有序集合进行编码。
5、有序集合命令的实现
——written by linhxx 2017.09.01
- 构建离线web应用(一)
- WCDB 的 WAL 模式和异步 Checkpoint
- Dotnet 2.0配置系统
- 小程序-实现竖排文字(二)
- 仿淘宝收货地址,本地数据库
- 小程序-实现竖排文字
- 【深度学习量化投资】RNNs在股票价格预测的应用基于Keras
- 关于webview调用js出现has no method 'toString'
- 深入学习Apache Spark和TensorFlow
- 搭建 WPF 上的 UI 自动化测试框架
- ttf设置文字字体
- R语言构建追涨杀跌量化交易模型(附源代码)
- Apache Spark中使用DataFrame的统计和数学函数
- android进程 清理及activity栈管理
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法