Redis数据类型之Zset详解

  • Zset简介
    • Zset常用操作
    • 应用场景
  • Zset实现
    • 源码阅读
    • Zset—ziplist实现
      • 图解Zset—ziplist
    • Zset—字典(dict) + 跳表(zskiplist)实现
      • 源码阅读
      • 图解zskiplist

Zset简介

Redis 有序集合和Set集合一样也是 string 类型元素的集合,且不允许重复的成员。
    不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
    有序集合的成员是唯一的,但分数(score)却可以重复。分数重复的情况下后插入的排在后面

因为Zset的插入方法是找到第一个比当前插入数据分值大的数据,然后插入到它的左边,成为其前驱节点。

Zset常用操作

  • ZADD key score member [[score member]…] :往有序集合key中加入带分值元素
  • ZREM key member [member …] :从有序集合key中删除元素
  • ZSCORE key member :返回有序集合key中元素member的分值
  • ZINCRBY key increment member :为有序集合key中元素member的分值加上increment
  • ZCARD key :返回有序集合key中元素个数
  • ZRANGE key start stop [WITHSCORES] :正序获取有序集合key从start下标到stop下标的元素
  • ZREVRANGE key start stop [WITHSCORES] :倒序获取有序集合key从start下标到stop下标的元素
  • ZUNIONSTORE destkey numkeys key [key …] :并集计算
  • ZINTERSTORE destkey numkeys key [key …] :交集计算

应用场景

  • 各种实时 or 历史排行榜

Zset实现

ZSet 为有序的,自动去重的集合数据类型,ZSet 数据结构底层实现为 字典(dict) + 跳表(zskiplist) 。当数据比较少时,用 ziplist 编码结构存储。

  • zset-max-ziplist-entries : 设置ziplist编码下最大支持的元素个数默认128个 ,如超过则会使用字典(dict) + 跳表(zskiplist)模式;
  • zset-max-ziplist-value :设置ziplist编码下最大支持的单个元素所占字节数默认64byte,如超过则会使用字典(dict) + 跳表(zskiplist)模式;

源码阅读

/* ZADD方法中判断Zset是否存在并选择使用哪种数据结构代码块*/
zobj = lookupKeyWrite(c->db,key);
//查询对应的key在对应的db中是否存在,不存在则创建
if (zobj == NULL) {if (xx) goto reply_to_client; /* No key + XX option: nothing to do. *//** 如果 zset_max_ziplist_entries ==0 或者 元素的长度 > zset_max_ziplist_value*         则直接创建 skiplist 数据结构*        否则创建ziplist 压缩列表数据结构*/ if (server.zset_max_ziplist_entries == 0 ||server.zset_max_ziplist_value < sdslen(c->argv[scoreidx+1]->ptr)){zobj = createZsetObject();} else {zobj = createZsetZiplistObject();}// 关联对象到db dbAdd(c->db,key,zobj);
}  else {if (zobj->type != OBJ_ZSET) {addReply(c,shared.wrongtypeerr);goto cleanup;}
}
// 处理所有元素
for (j = 0; j < elements; j++) {double newscore;// 分值 score = scores[j];int retflags = flags;// 元素 ele = c->argv[scoreidx+1+j*2]->ptr;/** 往zobj 添加元素* 添加元素的zsetAdd方法会去判断当前的有序集合 encoding编码是 ziplist 还是 zset*       如果是ziplist 则添加元素时还需要判断元素中个数与大小是否超过阈值,如超出则转为zset编码*/int retval = zsetAdd(zobj, score, ele, &retflags, &newscore);//......省略后续代码
}

Zset—ziplist实现

当Zset的底层实现是 ziplist 时, ziplist 中的 entry 的个数永远是双数,是以 member score member score … member score 形式存储且每一次插入都保证有序。进行查询时,通过直接遍历ziplist,比对 score 的值来获取member 。

此处不再额外对ziplist源码进行阅读,如需了解请通过传送门查看ziplist具体实现:数据类型List实现源码详解

图解Zset—ziplist

假设我的zset中包含许多元素,而最小的两个分别为 :
zadd zset-ziplist 101 李四
zadd zset-ziplist 99 张三

Zset—字典(dict) + 跳表(zskiplist)实现

Zset其实可以看做一个根据 value排序的 hash集合,所以Zset中的 字典(dict) ,整体与 hash 的字典(dict) 实现基本一致为了迅速根据member 获取score,同时也可以用于判断 member是否存在。但是需要额外维护一个 跳表(zskiplist ) 用于排序。

说到有序集合的查找效率问题,当链表过深必然存在遍历缓慢问题,于是Redis选择用 空间换时间 采用 跳表(zskiplist) 方式,来做到一个接近 二分查找 的效率。
此处不再额外对dict源码进行阅读,如需了解请通过传送门查看dict具体实现:数据类型Hash实现源码详解

源码阅读

// zset的数据结构 dict + zskiplist
typedef struct zset {dict *dict;zskiplist *zsl;
} zset;// zskiplist跳表数据结构
typedef struct zskiplist {struct zskiplistNode *header, *tail;  //头、尾指针。方便正序或逆序遍历unsigned long length;      //元素总个数/** 跳跃表的节点中level最大的节点的level保存在该成员变量中。* 但是不包括头结点,头结点的level永远都是最大的值:ZSKIPLIST_MAXLEVEL = 32。* level的值随着跳跃表中节点的插入和删除随时动态调整*/ int level;
} zskiplist;/* * ZSET 使用专用版本的 Skiplist* 以下为zskiplist的每个节点的数据结构*     大家要注意这里的 level[] 这里是一个柔性数组*     所以关于从高层索引层向下层移动查找时并不是像很多博客中画图的指针指向下一层级!!!*/
typedef struct zskiplistNode {sds ele;          //member元素double score;     //分值,用于排序,可以相同struct zskiplistNode *backward;        //指向前驱节点的指针struct zskiplistLevel {//后继节点指针,这个指针只会指向与当前level同层级的下一个节点。(也就是跳表的核心索引了)struct zskiplistNode *forward;    unsigned long span;     //从当前节点到下一个节点的跨度} level[];          //索引数组,该成员是一种柔性数组
} zskiplistNode;

图解zskiplist

因图片较大特附上原件地址:https://www.processon.com/view/link/61ff6ace1efad479c07b0323

你的点赞就是我创作的最大动力,如果写的不错,来个三连行不行

Redis从精通到入门——数据类型Zset实现源码详解相关推荐

  1. Redis源码详解 - Replication(主备)流程

    HA(高可用性)是数据库的最基本需求,而主备冗余则是HA最基础的解决方案.Redis里面,主备通常使用Master-Replica来表述. 通用主备方案的实现,涉及到以下几个关键问题: 主备感知:主备 ...

  2. MySQL数据库,从入门到精通:第十四篇——MySQL视图详解

    MySQL数据库,从入门到精通:第十四篇--MySQL视图详解 第 14 篇_视图 1. 常见的数据库对象 2. 视图概述 2. 1 为什么使用视图? 2. 2 视图的理解 3. 创建视图 3. 1 ...

  3. 2接口详解_TS入门笔记2——TS接口进阶详解

    TS入门笔记--TS接口进阶详解 一.为什么需要接口? let obj:object; // 定义了一个只能保存对象的变量 // obj = 1; // obj = "123"; ...

  4. ElasticSearch最全详细使用教程:入门、索引管理、映射详解

    墨墨导读:本文介绍了ElasticSearch的必备知识:从入门.索引管理到映射详解. 一.快速入门 1. 查看集群的健康状况http://localhost:9200/_cat http://loc ...

  5. pythontuple数据类型_Python数据类型之Tuple元组实例详解

    本文实例讲述了Python数据类型之Tuple元组.分享给大家供大家参考,具体如下: tuple元组 1.概述 本质上是一种有序的集合,和列表非常的相似,列表使用[]表示,元组使用()表示. 特点:一 ...

  6. python中列表数据类型_Python数据类型之List列表实例详解

    本文实例讲述了Python数据类型之List列表.分享给大家供大家参考,具体如下: list列表 1.概述: 通过之前的学习,我们知道变量可以存储数据,但是一个变量只能存储一个数据,现在有一个班级,班 ...

  7. mysql防止超发_PHP+redis实现的限制抢购防止商品超发功能详解

    本文实例讲述了PHP+redis实现的限制抢购防止商品超发功能.分享给大家供大家参考,具体如下: redis不仅仅是单纯的缓存,它还有一些特殊的功能,在一些特殊场景上很好用.redis中key的原子自 ...

  8. java中batch基础_详解Spring batch 入门学习教程(附源码)

    详解Spring batch 入门学习教程(附源码) 发布时间:2020-09-08 00:28:40 来源:脚本之家 阅读:99 作者:achuo Spring batch 是一个开源的批处理框架. ...

  9. python对输入的字符串进行解析_python数据类型_字符串常用操作(详解)

    这次主要介绍字符串常用操作方法及例子 1.python字符串 在python中声明一个字符串,通常有三种方法:在它的两边加上单引号.双引号或者三引号,如下: name = 'hello' name1 ...

最新文章

  1. jQuery UI 1.10.1 发布
  2. 电气simulink常用模块_16种常用模块电路分析,电气工程师的必备
  3. 回归专题 | regression
  4. HDU2255(带权二分图的最大匹配)
  5. java中的线程不安全和实例解析
  6. python3socket非阻塞在linux里无效_Linux下socket设置为非阻塞方式和fcntl系统调用
  7. CorelDRAWX4的VBA插件开发(七)形状的静态编号和一键转位图
  8. bzoj 4568 [Scoi2016]幸运数字
  9. php mb_eregi_replace 只替换一个,php正则ereg ereg_replace eregi eregi_replace split
  10. Microsoft Azure 建立虚拟机
  11. 挽救市场信誉度,三星正面回应手机爆炸缘由
  12. charles常用功能使用说明
  13. nodejs http调用报错:socket hang up
  14. 如何选择靠谱的游戏音乐外包呢?
  15. 大龄程序员的前途在哪里?
  16. conda安装jupyter notebook,解决无法远程
  17. 谷歌创始人拉里·佩奇和谢尔盖·布林发表了论文 The Pagerank Citation Rank :Bringing Order to the Web...
  18. 棋盘问题 51Nod - 1605
  19. R产生指定协方差阵的正态随机向量
  20. 执行linux 脚本的时候提示没有权限

热门文章

  1. 姜小白的Python日记Day14 系统模块详解1 time模块和random模块
  2. 如何对一个水杯进行测试?(详细)
  3. 划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚一杯酒。两人同赢或两人同输
  4. 10岁小表妹也能“吃透”Geth 客户端 !360秒,快速部署 ICO Token
  5. 利用 EXE4j 生成 .exe Java Swing程序
  6. 用狼的处世哲学做SOHO 一
  7. 2022.11.16 英语背诵
  8. 什么是DirectX
  9. 他,1年9个月获清华博士学位,一作身份发27篇SCI,组队击败NASA打破“航天奥林匹克”欧美垄断...
  10. java jpress,JPress导入Eclipse