Redis数据结构SortedSet的底层原理解析

 更新时间:2022年07月13日 15:59:08   作者:空指针异常1  
这篇文章主要介绍了Redis数据结构SortedSet的底层原理解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

概述

一些常用命令

  • 存储:zadd key score value
  • 获取:zrange key start end
  • 获取:同时获取分数:zrange key start end with score
  • 删除:zrem key value

存储的时候我们可以发现,是有一个score(分数)的,这个就是用来排序的字段。

实现

先说结论,SortedSet底层,根据配置会在不同的时候选用两种不同的数据结构zset,或ziplist进行存储:

首先,我们来看几个参数:

zset-max-ziplist-entries 128
zset-max-ziplist-value 64
if (
    field-value对的数量 > ziplist.entries.size ||
    任意一个filed或value长度 > zset-max-ziplist-value
) {
    // 使用 zset 进行存储
} else {
    // 使用 ziplist 进行存储

zset的结构如下:

typedef struct zset {
    dict *dict;
    zskiplist *zsl;
} zset

可以发现,是由字典+跳跃表实现的。

  • zset 结构体里有两个元素,一个是 dict,用来维护 数据 到 分数 的关系,一个是 zskiplist,用来维护 分数所在链表 的关系
  • dict 里通过维护 哈希表 存储了 张三=>100,李四=>90 的分数关系。

而跳表则是排序的关键

跳跃表

先上图:

我们知道,链表的检索效率是非常低的,如果要拿到100条数据中间的数据,则需要遍历50个数据才行,为了解决这个问题,跳表应运而生

如上图,就是常规的跳表,会在原有的数据上加上若干层,指向当前层的下一个节点。

跳表的插入

如上图所示:其实每个节点的层数是随机的,而且新插入一个节点不会影响其它节点的层数。因此,插入操作只需要修改插入节点前后的指针,而不需要对很多节点都进行调整。这就降低了插入操作的复杂度。实际上,这是skiplist跳表的一个很重要的特性,这让它在插入性能上明显优于平衡树的方案。

如下图,假如我们需要查询23,查询的路径如下。

事实上,在插入之前也要先经历一个类似的查找过程,在确定插入位置后,再完成插入操作。

这也是SortedSet实现排序的原理。

压缩列表

压缩列表 ziplist 是为 Redis 节约内存而开发的。

压缩列表是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意多个节点 (entry),每个节点可以保存 一个字节数组 或者 一个整数值 。

1、zl bytes:用于记录整个压缩列表占用的内存字节数

2、zl tail:记录要列表尾节点距离压缩列表的起始地址有多少字节

3、zl len:记录了压缩列表包含的节点数量。

4、entryX:要说列表包含的各个节点

5、zl end:用于标记压缩列表的末端

压缩列表是一种为了节约内存而开发的顺序型数据结构

压缩列表被用作列表键和哈希键的底层实现之一

压缩列表可以包含多个节点,每个节点可以保存一个字节数组或者整数值

添加新节点到压缩列表,可能会引发连锁更新操作。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • redis反序列化报错原因分析以及解决方案

    redis反序列化报错原因分析以及解决方案

    这篇文章主要介绍了redis反序列化报错原因分析以及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • redis 替代php文件存储session的实例

    redis 替代php文件存储session的实例

    这篇文章主要介绍了redis 替代php文件存储session的实例的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下
    2017-10-10
  • redis的hGetAll函数的性能问题(记Redis那坑人的HGETALL)

    redis的hGetAll函数的性能问题(记Redis那坑人的HGETALL)

    这篇文章主要介绍了redis的hGetAll函数的性能问题,需要的朋友可以参考下
    2016-02-02
  • 从一个小需求感受Redis的独特魅力(需求设计)

    从一个小需求感受Redis的独特魅力(需求设计)

    Redis在实际应用中使用的非常广泛,本篇文章就从一个简单的需求说起,为你讲述一个需求是如何从头到尾开始做的,又是如何一步步完善的
    2019-12-12
  • Redis底层数据结构SkipList的实现

    Redis底层数据结构SkipList的实现

    本文主要介绍了Redis底层数据结构SkipList的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Redis分片集群存储的搭建到使用

    Redis分片集群存储的搭建到使用

    这篇文章主要介绍了Redis分片集群存储的搭建到使用,分片集群顾名思义,将数据分开存储到Redis集群中,这样能够存储更多的数据,避免浪费资源,需要的朋友可以参考下
    2022-06-06
  • 在K8s上部署Redis集群的方法步骤

    在K8s上部署Redis集群的方法步骤

    这篇文章主要介绍了在K8s上部署Redis集群的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • redis击穿 雪崩 穿透超详细解决方案梳理

    redis击穿 雪崩 穿透超详细解决方案梳理

    这篇文章主要为大家介绍了Redis击穿穿透雪崩产生原因及解决思路的解决方案参考,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步
    2022-03-03
  • Redis中set类型实现交集并集差集

    Redis中set类型实现交集并集差集

    本文主要介绍了Redis中set类型实现交集并集差集,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Redis教程(十五):C语言连接操作代码实例

    Redis教程(十五):C语言连接操作代码实例

    这篇文章主要介绍了Redis教程(十五):C语言连接操作代码实例,本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例,需要的朋友可以参考下
    2015-05-05

最新评论