Redis中有序集合的内部实现方式的详细介绍


Posted in Redis onMarch 16, 2022

面试官:Redis中基本的数据类型有哪些?

我:Redis的基本数据类型有:字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。

面试官:有序集合的内部实现方式是什么?

我还沉浸在上一个问题的沾沾自喜中,顿时表情凝固了,手心开始冒出冷汗。“这个。。没有太深入了解”,我支支吾吾的说到。

面试官:回去等消息吧。

这句话说的干净利落,然后就没有然后了。失败是成功的妈妈,我不气馁,决定马上恶补一下。

有序集合的内部实现

有序集合的内部实现有两种,分别是:压缩列表(ziplist)和跳跃表(skiplist)。接下来,我们分别进行详细的了解。

以压缩列表作为内部实现

当有序集合的元素个数小于zset-max-ziplist-entries(默认为128个),并且每个元素成员的长度小于zset-max-ziplist-value(默认为64字节)的时候,使用压缩列表作为有序集合的内部实现。

每个集合元素由两个紧挨在一起的两个压缩列表结点组成,其中第一个结点保存元素的成员,第二个结点保存元素的分支。压缩列表中的元素按照分数从小到大依次紧挨着排列,有效减少了内存空间的使用。

举个例子,我们使用zadd命令创建一个以压缩列表为实现的有序集合:

127.0.0.1:6379> zadd one-more-zset 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrange one-more-zset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> object encoding one-more-zset
"ziplist"

以跳跃表作为内部实现

当有序集合的元素个数大于等于zset-max-ziplist-entries(默认为128个),或者每个元素成员的长度大于等于zset-max-ziplist-value(默认为64字节)的时候,使用跳跃表作为有序集合的内部实现。

此时,在有序集合中其实包含了两个结构,一个是跳跃表,另一个是哈希表。

在跳跃表中,所有元素按照从小到大的顺序排列。跳跃表的结点中的object指针指向元素成员的字符串对象,score保存了元素的分数。通过跳跃表,Redis可以快速地对有序集合进行分数范围、排名等操作。

在哈希表中,为有序集合创建了一个从元素成员到元素分数的映射。键值对中的键指向元素成员的字符串对象,键值对中的值保存了元素的分数。通过哈希表,Redis可以快速查找指定元素的分数。

虽然有序集合同时使用跳跃表和哈希表,但是这两种数据结构都使用指针共享元素中的成员和分数,不会额外的内存浪费。

举个例子,我们使用zadd命令创建一个以跳跃表为实现的有序集合:

127.0.0.1:6379> zadd one-more-zset 1 long-long-long-long-long-long-long-long-long-long-long-long-long-long
(integer) 1
127.0.0.1:6379> zrange one-more-zset 0 -1
1) "long-long-long-long-long-long-long-long-long-long-long-long-long-long"
127.0.0.1:6379> object encoding one-more-zset
"skiplist"

内部实现的转换

当一个有序集合是以压缩列表作为内部实现时,再向这个有序集合添加较长的元素成员,或向这个有序集合的元素个数过多时,那么这个有序集合就会转换为以跳跃表作为内部实现。但是,以跳跃表作为内部实现的有序集合不会转换为以压缩列表作为内部实现。

举个例子,我们先创建一个以压缩列表作为内部实现的有序集合:

127.0.0.1:6379> zadd one-more-zset 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrange one-more-zset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> object encoding one-more-zset
"ziplist"

然后,再向它添加一个较长成员的元素,它就是转换为以跳跃表作为内部实现:

127.0.0.1:6379> zadd one-more-zset 4 long-long-long-long-long-long-long-long-long-long-long-long-long-long
(integer) 1
127.0.0.1:6379> zrange one-more-zset 0 -1
1) "one"
2) "two"
3) "three"
4) "long-long-long-long-long-long-long-long-long-long-long-long-long-long"
127.0.0.1:6379> object encoding one-more-zset
"skiplist"

然后,再把那一个较长成员的元素从有序集合中移除,有序集合依然是以跳跃表作为内部实现:

127.0.0.1:6379> zrem one-more-zset long-long-long-long-long-long-long-long-long-long-long-long-long-long
(integer) 1
127.0.0.1:6379> zrange one-more-zset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> object encoding one-more-zset
"skiplist"

总结

在Redis中,有序集合的内部实现有压缩列表(ziplist)和跳跃表(skiplist)两种,当集合中的所有元素的成员长度较短并元素个数较少时,使用压缩列表作为内部实现,否则使用跳跃表和哈希表作为内部实现。当条件不满足时,压缩列表可以转换为跳跃表,但跳跃表不能转换为压缩列表。

到此这篇关于Redis中有序集合的内部实现方式的详细介绍的文章就介绍到这了,更多相关Redis有序集合的内部实现内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
redis实现排行榜功能
May 24 Redis
比较几种Redis集群方案
Jun 21 Redis
Redis缓存-序列化对象存储乱码问题的解决
Jun 21 Redis
压缩Redis里的字符串大对象操作
Jun 23 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
Redis调用Lua脚本及使用场景快速掌握
Mar 16 Redis
Redis如何实现验证码发送 以及限制每日发送次数
Apr 18 Redis
浅谈Redis的事件驱动模型
May 30 Redis
Redis基本数据类型List常用操作命令
Jun 01 Redis
Redis实现分布式锁的五种方法详解
Jun 14 Redis
关于Redis的主从复制及哨兵问题
Jun 16 Redis
redis protocol通信协议及使用详解
Jul 15 Redis
面试分析分布式架构Redis热点key大Value解决方案
分布式架构Redis中有哪些数据结构及底层实现原理
Redis之RedisTemplate配置方式(序列和反序列化)
Mar 13 #Redis
浅谈Redis跟MySQL的双写问题解决方案
解决linux下redis数据库overcommit_memory问题
Feb 24 #Redis
解决Redis启动警告问题
分布式Redis Cluster集群搭建与Redis基本用法
You might like
PHP 循环列出目录内容的函数代码
2010/05/26 PHP
PHP 防注入函数(格式化数据)
2011/08/08 PHP
php变量范围介绍
2012/10/15 PHP
php将日期格式转换成xx天前的格式
2015/04/16 PHP
详谈PHP编码转换问题
2015/07/28 PHP
解读PHP中的垃圾回收机制
2015/08/10 PHP
laravel自定义分页效果
2017/07/23 PHP
laravel 创建命令行命令的图文教程
2019/10/23 PHP
Gambit vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
更正确的asp冒泡排序
2007/05/24 Javascript
JQuery 选择和过滤方法代码总结
2010/11/19 Javascript
JavaScript作用域链示例分享
2014/05/27 Javascript
基于jquery实现下拉框美化特效
2016/02/02 Javascript
JavaScript过滤字符串中的中文与空格方法汇总
2016/03/07 Javascript
jquery获取复选框checkbox的值的简单实现方法
2016/05/26 Javascript
Js动态设置rem来实现移动端字体的自适应代码
2016/10/14 Javascript
jQuery实现CheckBox全选、全不选功能
2017/01/11 Javascript
xmlplus组件设计系列之分隔框(DividedBox)(8)
2017/05/02 Javascript
Angularjs修改密码的实例代码
2017/05/26 Javascript
微信小程序实现传递多个参数与事件处理
2019/08/12 Javascript
python中的列表推导浅析
2014/04/26 Python
Python爬虫实现爬取京东手机页面的图片(实例代码)
2017/11/30 Python
Python2和Python3.6环境解决共存问题
2018/11/09 Python
python3实现钉钉消息推送的方法示例
2019/03/14 Python
详解用python自制微信机器人,定时发送天气预报
2019/03/25 Python
pygame实现俄罗斯方块游戏(基础篇2)
2019/10/29 Python
python中的TCP(传输控制协议)用法实例分析
2019/11/15 Python
关于Numpy数据类型对象(dtype)使用详解
2019/11/27 Python
Python tkinter布局与按钮间距设置方式
2020/03/04 Python
jupyter notebook 实现matplotlib图动态刷新
2020/04/22 Python
python判断正负数方式
2020/06/03 Python
python实现代码审查自动回复消息
2021/02/01 Python
估算杭州有多少软件工程师
2015/08/11 面试题
感情真挚的毕业生求职信
2014/07/19 职场文书
2015年南京大屠杀纪念日活动总结
2015/03/24 职场文书
在酒桌上的敬酒词
2015/08/12 职场文书