【Redis】集合Set和底层实现

news2024/11/25 0:23:11

文章目录

  • Redis 集合(Set)
    • Set简介
    • 常用命令
    • 应用场景
      • 共同关注实例
  • 整数集合
    • 整数集合介绍
    • 整数集合的升级
  • 哈希表
    • 哈希表的原理和实现
    • Redis中的哈希表
    • rehash
      • 渐进式rehash

Redis 集合(Set)

Set简介

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

Redis的Set是string类型的无序集合。它底层其实是一个value为null的哈希表或者整数集合,所以添加,删除,查找的复杂度都是O(1)。

  • 如果集合中的元素都是整数且元素个数小于 512 (默认值,set-maxintset-entries配置)个,Redis 会使用整数集合作为 Set 类型的底层数据结构;
  • 如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为 Set 类型的底层数据结构。

image-20221213164818506

一个集合最多可以存储 2^32-1 个元素。概念和数学中个的集合基本类似,可以交集,并集,差集等等,所以 Set 类型除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集。

常用命令

向集合中添加元素

  • sadd …

image-20221213162236926

查看集合中的值

  • smembers

image-20221213162352183

判断一个元素是否在集合中

  • sismember 判断集合是否为含有该值,有1,没有0

image-20221213162712755

集合的元素个数。

  • scard返回该集合的元素个数。

image-20221213163023345

Set的删除和取值

  • srem … 删除集合中的某个元素。
  • spop 随机从该集合中吐出一个值。
  • srandmember 随机从该集合中取出n个值。不会从集合中删除 。

image-20221213163341036

集合间运算

  • smove value把集合中一个值从一个集合移动到另一个集合
  • sinter 返回两个集合的交集元素。
  • sunion 返回两个集合的并集元素。
  • sdiff 返回两个集合的差集元素(key1中的,不包含key2中的)

image-20221213164232181

集合的运算

  • sinterstore destination key [ key… ]将交集的结果存入新集合destination中
  • sunionstore destination key [ key… ]将并集结果存入新集合destination中
  • sdiffstore destination key [ key…] 将差集结果存入新集合destination中

image-20221213170905474

应用场景

因此 Set 类型比较适合用来数据去重和保障数据的唯一性,还可以用来统计多个集合的交集、错集和并集等,当我们存储的数据是无序并且需要去重的情况下,比较适合使用集合类型进行存储。

Set 的差集、并集和交集的计算复杂度较高,在数据量较大的情况下,如果直接执行这些计算,会导致 Redis 实例阻塞

共同关注实例

Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。key 可以是用户id,value 则是已关注的公众号的id。

image-20221213171837202

uid1 和 uid2共同关注的公众号

image-20221213171948168

uid:1 向uid:2 推荐公众号

image-20221213172041481

验证某个公众号是否同时被 uid:1uid:2 关注:

image-20221213172241379

number6公众号被uid:1和uid:2同时关注

整数集合

整数集合介绍

当一个 Set 对象只包含整数值元素,并且元素数量不大时,就会使用整数集这个数据结构作为底层实现。

整数集合本质上是一块连续内存空间

typedef struct intset {
    //编码方式
    uint32_t encoding;
    //集合包含的元素数量
    uint32_t length;
    //保存元素的数组
    int8_t contents[];
} intset;

contents数组中的数据类型取决于encoding的取值类型

  • 如果 encoding 属性值为 INTSET_ENC_INT16,那么 contents 就是一个 int16_t 类型的数组,数组中每一个元素的类型都是 int16_t;
  • 如果 encoding 属性值为 INTSET_ENC_INT32,那么 contents 就是一个 int32_t 类型的数组,数组中每一个元素的类型都是 int32_t;
  • 如果 encoding 属性值为 INTSET_ENC_INT64,那么 contents 就是一个 int64_t 类型的数组,数组中每一个元素的类型都是 int64_t;

整数集合的升级

当我们将一个新的元素插入到整数集合中,如果新加入元素类型比整数集合现有所有元素类型都要长,整数集合就需要升级。按照整数集合中最长类型进行升级。

整数集合升级的过程不会重新分配一个新类型的数组,而是在原本的数组上扩展空间

在升级的过程中,要保证底层数组的有序性不变。

比如原数组中有1,2,3三个元素

image-20221213182407490

此时向数组中插入一个65535

原数组中int16_t类型需要升级为int32_t类型,首先进行扩容。

image-20221213182526308

然后按照顺序,将原元素放入到正确的位置。该过程中要保证元素的顺序保持不变。

image-20221213182705333

image-20221213182730938

image-20221213182740843

向整数集合中添加新的元素

image-20221213182804244

整数升级的最大好处就是可以有效的节约资源。

哈希表

哈希表的原理和实现

关于哈希表的实现和介绍:

哈希表的原理和实现

位图、布隆过滤器和一致性哈希

Redis中的哈希表

Redis中哈希采用链式结构存储数据

typedef struct dictht {
    //哈希表数组
    dictEntry **table;
    //哈希表大小
    unsigned long size;  
    //哈希表大小掩码,用于计算索引值
    unsigned long sizemask;
    //该哈希表已有的节点数量
    unsigned long used;
} dictht;

image-20221213214949713

哈希表dictEnty中的每一个元素指向一个链表。链表的每个节点是哈希表结点。

哈希表结点的定义

typedef struct dictEntry {
    //键值对中的键
    void *key;
  
    //键值对中的值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    //指向下一个哈希表节点,形成链表
    struct dictEntry *next;
} dictEntry;

rehash

rehash,也就是对哈希表的大小进行扩展。实际应用中,Redis定义一个dict 结构体,这个结构体里定义了两个哈希表,用于rehash

typedef struct dict {//两个Hash表,交替使用,用于rehash操作
    dictht ht[2];} dict;

image-20221213221301241

在对哈希表进行扩展时,就需要使用上两个哈希表。

在正常服务请求阶段,插入的数据,都会写入到「哈希表 1」,此时的「哈希表 2 」 并没有被分配空间。随着数据的进一步添加,达到了rehash的条件:

  • 给「哈希表 2」 分配空间,一般会比「哈希表 1」 大 2 倍;
  • 将「哈希表 1 」的数据迁移到「哈希表 2」 中;
  • 迁移完成后,「哈希表 1 」的空间会被释放,并把「哈希表 2」 设置为「哈希表 1」,然后在「哈希表 2」 新创建一个空白的哈希表,为下次 rehash 做准备。

image-20221213221805539

渐进式rehash

为了避免 rehash 在数据迁移过程中,因拷贝数据的耗时,影响 Redis 性能的情况,所以 Redis 采用了渐进式 rehash,也就是将数据的迁移的工作不再是一次性迁移完成,而是分多次迁移。

  • 在rehash进行期间,每次哈希元素进行增删改查操作时,redis除了执行对应的操作,还会顺序将哈希表1中索引位置上的所有key-value迁移到哈希表2中。
  • 直到某个时间段,哈希表1的所有key-value都被迁移到哈希表2中,此时完成了rehash操作。

注意:

在进行渐进式rehash的过程中,存在两个哈希表,因此哈希表的增删查改操作,都会在两个表中进行。

  • 在查找元素时,会先在哈希表1中查找,如果没有找到,就会在哈希表2中查找。
  • 在添加元素时,元素会被保存在哈希表2中;删除元素,先删除哈希表1中的元素,如果没有,再删除哈希表2中的元素。这样,保证了哈希表1的数据只减少,随着操作进行,哈希表1最后会变成一个空表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多维时序 | MATLAB实现GRU多变量时间序列预测

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

c语言中fread,fgets等取文件字符的缓存空间小出现问题

一种奇怪现象 #include <stdio.h> #include <stdlib.h> #include<windows.h>int main(void){int i;printf("hello\n");fflush(stdout); //当没有这部刷新&#xff0c;hello会和end等到时间一起输出Sleep(2000); //windowsa.h中的Sleep&#…

某研究生不写论文竟研究起了算命?

起因 大约一个月前&#xff0c;在学校大病一场&#xff08;不知道是不是&#x1f411;了&#xff0c;反正在学校每天核酸没检测出来&#xff09;在宿舍休息了整整一周。当时因为发烧全身疼所以基本一直躺着刷刷视频。看了一周倪海厦老师讲的天纪&#xff0c;人纪感悟颇多&…

央企招聘:中国航空油料集团2023公开招聘

一、公司简介 中国航空油料集团有限公司&#xff08;以下简称“中国航油”&#xff09;成立于2002年10月11日&#xff0c;是以原中国航空油料总公司为基础组建的国有大型航空运输服务保障企业&#xff0c;是国内最大的集航空油品采购、运输、储存、检测、销售、加注为一体的航…

Spring Boot打成jar包后运行及配置文件的问题

Maven打包 因为Spring Boot项目内置Tomcat&#xff0c;所以可以打成一个jar包直接运行&#xff0c;而不必再需要安装Tomcat了。 如果用IDEA打包&#xff0c;还得先添加Artifacts&#xff1a; 然后再选择‘Main Class’ 显然比较麻烦&#xff0c;而且每次导入项目都得重新添加…

高频功率放大器工作原理总结(高频和低频功率放大器的区别)

高频功率放大器处在发射机的末级&#xff0c;主要作用是把高频已调拨信号进行功率放大&#xff0c;满足发送功率的要求&#xff0c;然后通过天线辐射到空间&#xff0c;保证一定区域接收机能够接收到信号电平。 高频功率放大器是通信系统中发送装置的组件&#xff0c;按照频带的…

【DOTS学习笔记】Cache层级结构与排队管理

目录前言如何理解L1,L2,L3级缓存的树形结构设计排队的烦恼现实中的排队烦恼计算机程序设计中的排队队列类型前言 本文是Metaverse大衍神君的《DOTS之路》系列课程的学习笔记 如何理解L1,L2,L3级缓存的树形结构设计 排队的烦恼 现实中的排队烦恼 这是一张关于排队的图&#xf…

论文速递:AAAI 2023 | 优图16篇论文速览,含多标签分类、姿态估计、目标检测、HOI、小样本学习等研究方向

近日&#xff0c;AAAI 2023&#xff08;Association for the Advancement of Artificial Intelligence&#xff09;国际先进人工智能协会公布了录用结果&#xff0c;本届会议共有8777篇投稿&#xff0c;录用1721篇&#xff0c;录用率19.6%。 AAAI是人工智能领域的主要学术组织之…

[go 语言学习笔记] 7天用Go从零实现分布式缓存GeeCache 「持续更新中」

说明 本文用于记录学习 go 语言过程中的笔记, 文中的代码都是在文本中敲出来的伪代码, 并不能直接运行, 如有需要可以参考原文链接. 本文的整体思路是对原系列教程阅读后的复盘. 关于本文参考的 学习教程 可以访问原教程链接: 7天用Go从零实现分布式缓存GeeCache 本文如有…

文本检测识别技术在合合信息的应用实务解决方案

合合信息保险行业全业务流程数字化解决方案 合合信息依托AI大数据&#xff0c;打造了保险行业全业务流程数字化解决方案&#xff1a;OCR智能分类识别文档、表格、卡证、票据、合同等&#xff0c;替代人工录入&#xff0c;图像智能质检优化&#xff0c;实现投保、核保、理赔、合…

(Matlab实现)基于蒙特卡洛模拟的大规模电动车充电模型

目录 摘要&#xff1a; 1电动车日行驶里程概率分布&#xff1a; 2.电动车充电起始时间概率分布&#xff1a; 3.大规模电动车充电行为蒙特卡洛建模&#xff1a; 3.1日行驶里程 3.2开始充电时间 3.3耗电量 3.4充电时间 3.5总充电负荷 4.不同规模的电动车的充电负荷曲线…

vue中vue-router安装与配置方法步骤详解

vue-router 是 vue.js 官方的路由插件&#xff0c;里面组件和 URL 的映射关系由 vue-route 帮我们管理。 在 vue-router 的单页面应用中&#xff0c;页面的路径的改变就是组件的切换。 第一步&#xff1a; 1.正常初始化项目的时候&#xff0c;会有个 vue-router 供我们选择。…

docker安装kafka、zookeeper

docker安装kafka、zookeeper 基于win10&#xff0c;docker desktop 基于linux也是一样的处理方式 (win10通过Docker搭建LNMP环境全流程)[https://blog.csdn.net/fendouweiqian/article/details/128062543] docker安装kafka、zookeeper 创建共享网络 为的是容器内可以通讯 …

vue-cli-3环境搭建和配置

一、vue 是单文件组件 之前注册组件有什么缺点 ? 1- 缺乏语法高亮 2-格式不好 3-没有专门的写css代码等等 参考 : vue > 工具 > 单文件组件 什么是单文件组件 &#xff1a;后缀为 .vue 的文件 单文件组件的三个组成部分 (代码块 : scaffold 自动提示) template (模…

21. 合理的模型初始化和激活函数

1. 让训练更加稳定 2. 让每层的方差是一个常数 以两个变量为例&#xff0c;均值为零可以让变量于自己的轴对称&#xff0c;那么在二维上整个变量分布就是中心对称&#xff0c;而方差则可以控制各个变量离原点的离散程度&#xff0c;那么就可以把二维变量看成限制在某个圈内。 在…

物联网开发笔记(61)- 使用Micropython开发ESP32开发板之控制3.2寸触摸屏的SD卡(续)

一、目的 这一节我们学习如何使用我们的ESP32开发板来控制3.2寸触摸屏的SD卡。 关键字&#xff1a;3.2寸SPI串口TFT液晶显示屏模块 ILI9341驱动 LCD触摸屏 240*320 XPT2046触摸屏芯片IC 二、环境 ESP32 3.2寸触摸屏SD卡模块 Thonny IDE 几根杜邦线 接线方法&#xff1a; …

[附源码]计算机毕业设计的中点游戏分享网站Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

一篇文章带你深入了解JavaScript中let+var的特性

暂时性死区 上篇文章我们了解到了let和var之间的细微差别&#xff0c;同时它们之间还有一个区别就是let声明的变量不会在作用域中被提升 <script> //name会被提升console.log(name); //undefinedvar name "Matt"; ​//age不会被提升console.log(age); //…

5.Naocs系列之集群部署

本文学习nacos基于docker的集群部署 1. 新增mysql8 Dockerfile文件 // online/shenjian/nacos/nacosCluster/image/mysql FROM mysql:8.0.30 ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/…

极客时间Kafka - 13 Kafka 中的高水位和 Leader Epoch 机制

文章目录1. 什么是高水位&#xff1f;2. 高水位的作用3. 高水位更新机制1. Leader 副本高水位更新机制2. Follower 副本高水位更新机制4. 副本同步机制解析5. Leader Epoch你可能听说过高水位&#xff08;High Watermark&#xff09;&#xff0c;但不一定耳闻过 Leader Epoch。…