【Redis】新增数据结构

2023-10-29

BitMap位图

Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:

(1) Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。

(2) Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。

常用命令

1.setbit 设置位图

setbit设置Bitmaps中某个偏移量的值(0或1)

  • offset:偏移量

2.getbit 获取位图

getbit获取Bitmaps中某个偏移量的值

3.bitcount 获取指定范围内值为1的个数

bitcount key start end

4、bitop

bitop [ operations ] [ result ] [key1] [keyn…]

  • bitop是一个复合操作, 它可以做多个Bitmaps的and(交集) 、 or(并集) 、 not(非) 、 xor(异或) 操作并将结果保存在destkey中。

应用场景

Bitmap 类型非常适合二值状态统计的场景,这里的二值状态就是指集合元素的取值就只有 0 和 1 两种,在记录海量数据时,Bitmap 能够有效地节省内存空间。

统计打卡情况

对于一天,如果签到了,就使用1表示,否则就用0表示。

比如下面,我们统计uid为1000的用户在2022年12月份的签到情况:

image-20221214091534451

用setbit设置一天是否签到;用getbit获取一天是否签到。

获取12月份一共签到了几天

image-20221214091816221

HyperLogLog

在实际需求中,我们经常会遇到与统计相关的功能需求,比如统计网站PV(PageView页面访问量),可以使用Redis的incr、incrby实现。

但像UV(UniqueVisitor,独立访客)、独立IP数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。

  • 在MySQL中,使用distinct count计算不重复个数
  • 在Redis中,可以使用hash、set、bitmaps等数据结构来处理

以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于海量数据是不切实际的。

HyperLogLog概念

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

HyperLogLog 是统计规则是基于概率完成的,不是非常准确,标准误算率是 0.81%。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

命令

1、pfadd

pfadd < element> [element …] 添加指定元素到 HyperLogLog 中

2、pfcount

pfcount [key …] 计算HyperLogLog的近似基数,可以计算多个HLL。

3、pfmerge

pfmerge [sourcekey …] 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得

应用场景

网页UV计算

使用pfadd把访问网页的用户添加到HLL中。

image-20221214100704438

统计第一天的访问基数

image-20221214100812128

合并前三天的访问基数

image-20221214101238353

Geospatial

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

GEO 本身并没有设计新的底层数据结构,而是直接使用了 Sorted Set 集合类型。GEO 类型使用 GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换。

常用命令

1、geoadd

geoadd < longitude> [longitude latitude member…] 添加地理位置(经度,纬度,名称)

实例:

geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing

2、geopos

geopos [member…] 获得指定地区的坐标值

实例:

geopos china:city chongqing

3、geodist

geodist [m|km|ft|mi ] 获取两个位置之间的直线距离

实例:

geodist china:city chongqing beijing km

4、georadius

georadius< longitude>radius m|km|ft|mi 以给定的经纬度为中心,找出某一半径内的元素

实例:

georadius china:city 110 30 1000 km

应用场景

比如我们在地图上计算两个城市之间的地理关系:

image-20221214103424274

Stream

Redis 专门为消息队列设计的数据类型。

在Stream没有出来以前。消息队列的实现方式或多或少都有一些缺陷:

  • 发布订阅模式,不能持久化也就无法可靠的保存消息,并且对于离线重连的客户端不能读取历史消息的缺陷;
  • List 实现消息队列的方式不能重复消费,一个消息消费完就会被删除,而且生产者需要自行实现全局唯一 ID。

Stream类型,用于完美的实现消息队列;

支持消息的持久化,支持自动生成的全局唯一ID,支持ack确认消息模式,支持消费组模式等。提供了稳定和可靠的消息队列实现。

常用命令

# 插入消息,保证有序,可以自动生成的全局唯一ID
XADD

# 查询消息长度
XLEN

#用于读取信息,可以按照ID读取数据
XREAD:用于读取消息,可以按 ID 读取数据;

#根据消息 ID 删除消息
XDEL

#删除整个Stream
DEL

#读取区间消息
XRANGE

#按消费组形式读取消息
XREADGROUP

# 用来查询每个消费组内所有消费者「已读取、但尚未确认」的消息;
XPENDING

#用于向消息队列确认消息处理已完成;
XACK

应用场景

生产者插入一条消息

# * 表示让Redis为插入数据自动生成一个全局唯一的ID
# 往命令为mymq的消息队列中插入一条消息。消息键是name 值是west

>XADD mymq * name west
"1670987339049-0"

消息ID的组成

  • 第一部分“1670987339049”是数据插入时,以毫秒为单位计算的当前服务器时间
  • 第二部分,“-0”表示当前毫秒内,插入的第一条消息,序号从0开始。

消费者通过 XREAD 命令从消息队列中读取消息

读取消息时,可以指定一个消息 ID,并从这个消息 ID 的下一条消息开始进行读取(注意是输入消息 ID 的下一条信息开始读取,不是查询输入ID的消息)。

# 因为我们上面只插入了一条消息,所以消息ID一定要小于想要读取的ID

XREAD STREAMS mymq 1670987339048-0

image-20221214111934739

  • 如果想要实现阻塞读取,可以调用 XRAED 时设定 BLOCK 配置项,单位是毫秒
  • 当消息队列中没有数据时,XREAD也会发生阻塞
XREAD BLOCK 10000 STREAMS mymq $

image-20221214112313311

XREAD和XADD的通信模型

image-20221214112427770

使用 xadd 存入消息和 xread 循环阻塞读取消息的方式可以实现简易版的消息队列

Stream特性

消费组

Stream 可以以使用 XGROUP 创建消费组,创建消费组之后,Stream 可以使用 XREADGROUP 命令让消费组内的消费者读取消息。

# 创建一个名为 group1 的消费组,0-0 表示从第一条消息开始读取
127.0.0.1:6379> XGROUP CREATE mymq group1 0-0
OK
# 创建一个名为 group2 的消费组
127.0.0.1:6379> XGROUP CREATE mymq group2 0-0
OK

image-20221214112844435

消费组 group1 内的消费者 consumer1 从 mymq 消息队列中读取所有消息:

# 命令最后的参数“>”,表示从第一条尚未被消费的消息开始读取。

127.0.0.1:6379> XREADGROUP Group group1 consumer1 STREAMS mymq >
1) 1) "mymq"
   2) 1) 1) "1670987339049-0"
         2) 1) "name"
            2) "west"

image-20221214113237850

  • 消息队列中的消息一旦被消费组里的一个消费者读取了,就不能再被该消费组内的其他消费者读取了,即同一个消费组里的消费者不能消费同一条消息。

比如我们再执行上面的命令:

image-20221214113447458

  • 不同消费组的消费者可以消费同一条消息(前提条件:创建消息组的时候,不同消费组指定了相同位置开始读取消息)。
127.0.0.1:6379> XREADGROUP Group group2 consumer1 STREAMS mymq >
1) 1) "mymq"
   2) 1) 1) "1670987339049-0"
         2) 1) "name"
            2) "west"

image-20221214113628667

  • 使用消费组的目的是实现负载均衡,因此往往同一个消费组的不同消费者读取不同的消息,从而实现消息读取负载在多个消费者间是均衡分布的:
# 让 group2 中的 consumer1 从 mymq 消息队列中消费一条消息

127.0.0.1:6379> XREADGROUP Group group2 consumer1 COUNT 1 STREAMS mymq >
1) 1) "mymq"
   2) 1) 1) "1670989392669-0"
         2) 1) "field1"
            2) "value1"
# 让 group2 中的 consumer2 从 mymq 消息队列中消费2条消息

127.0.0.1:6379> XREADGROUP Group group2 consumer2 COUNT 2 STREAMS mymq >
1) 1) "mymq"
   2) 1) 1) "1670989404047-0"
         2) 1) "field2"
            2) "value2"
      2) 1) "1670989416512-0"
         2) 1) "field3"
            2) "value3"

image-20221214114726371

消息的可靠性

基于 Stream 实现的消息队列,如何保证消费者在发生故障或宕机再次重启后,仍然可以读取未处理完的消息?

Streams会使用PENDING List留存消费组每个消费者读取的消息,直到消费者使用XACK命令通知Streams消息已经被处理。

  • 如果消费者没有成功处理消息,它就不会给 Streams 发送 XACK 命令,消息仍然会留存。
  • 此时,消费者可以在重启后,用 XPENDING 命令查看已读取、但尚未确认处理完成的消息

image-20221214115448057

查看某个消费者具体读取了哪些数据,可以执行下面的命令:

XPENDING mymq group2 - + 10 consumer1

image-20221214115715555

消息处理完后,使用XACK通知消息队列,这条消息就会被删除

127.0.0.1:6379> XACK mymq group2 1670987339049-0 1670989200775-0 1670989392669-0
(integer) 3
127.0.0.1:6379> XPENDING mymq group2 - + 10 consumer1
(empty array)

image-20221214115905076

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Redis】新增数据结构 的相关文章

随机推荐

  • 架构知识体系

    架构安全 对已知问题有有效的解决方案 对未知 潜在问题建立发现和防御机制 对于安全问题 首先要提高安全意识 建立一个安全的有效机制 从政策层面 组织层面进行保障 比如服务器密码不能泄露 密码每月更新 并且三次内不能重复 每周安全扫描等 以制
  • Gradle Springboot Web热部署的设置

    前言 在我们平时开发当中 需要实时的要查看我们的编码效果 这个时候如果我们设置了热部署 就免去了我们频繁的重启本地项目 热部署我们需要用到spring boot devtools这个组件 这里我们采用的gradle来管理项目 所以采用的ma
  • LeetCode 226. 翻转二叉树

    题目链接 https leetcode cn com problems invert binary tree 先序遍历 Java 代码 class Solution public TreeNode invertTree TreeNode r
  • 我的世界ess服务器信息,我的世界ess指令怎么用 ess指令大全及用法详解

    我的世界ess指令都有哪些 作为风靡全球的沙盒游戏 我的世界带给玩家太多的乐趣 为了能更方便的游戏 ess指令能帮助我们更好的游戏 很多新手玩家刚接触就被搞晕了 这么多的指令看起来有些复杂 下面就由小编给大家带来 我的世界ess指令都有哪些
  • mybatis进行批量插入 返回批量插入主键ID 插入不成功等问题

    这篇博文讲的是批量插入的例子 dao层框架用的mybatis 最一开始我的批量插入其实是个伪批量 是类似吧很多条insert into语句 直接拼成一条 然后直接运行 发现这样的效率真的是十分低 我做测试时285条数据 插入一次需要10S多
  • uniapp添加.gitignore以及不生效解决办法

    一 第一次新建 gitignore 首先进入项目 命令行新建 gitignore文件 touch gitignore 然后编辑器打开 进入到项目中新建的 gitignore 文件 复制粘贴以下 node modules project un
  • C++实现鼠标点击其他程序

    1 主要是SendInput函数 代码如下 初始化 INPUT input 0 input type INPUT MOUSE dx dy代表的是进行点击的坐标 下面显示的是 950 150 input mi dx static cast
  • 【Proteus仿真】555组成的多谐振荡器电路

    Proteus仿真 555组成的多谐振荡器电路 Proteus仿真演示 多谐振荡器电路 多谐振荡器电路是一种矩形波产生电路 属于数字电路 三极管不工作在放大线性区 这种电路不需要外加触发信号便能连续地 周期性地自行产生矩形脉冲 该脉冲是由基
  • Stable Diffusion:ChatGPT与AI绘画,引领艺术的未来

    人工智能 AI 的快速发展正在为各个领域带来革命性的变化 其中包括艺术与创意领域 AI绘画是一种将人工智能技术与艺术创作相结合的新兴范式 通过深度学习和生成对抗网络 GAN 等技术 AI绘画可以生成各种富有创意和想象力的艺术作品 本文将探讨
  • python - __str__ 和 __repr__

    内建函数str 和repr representation 表达 表示 或反引号操作符 可以方便地以字符串的方式获取对象的内容 类型 数值属性等信息 str 函数得到的字符串可读性好 故被print调用 而repr 函数得到的字符串通常可以用
  • Docker+docker-compose+nginx部署已有项目

    项目背景 在异地服务器拷docker相关项目到新的服务器 具体操作 1 新服务器安装好docker 2 新服务器安装好docker compose 3 从老服务器拷贝镜像到新服务器 4 新服务器导入镜像 5 构建项目地址挂载目录 找到doc
  • 用U盘作启动盘装Windows10系统整套流程 纯净版(不用其他乱七八糟的软件)(macOS适用)

    简介 本人的电脑是MacBook Air 2014年版的 因为内存小而且文件杂乱 所以一下子都给格式化了 但是要用Mac自带的恢复系统的话需要连接校园网 连接校园网又需要打开网页输入账号和密码 我们学校的校园网是这样的 所以只能用U盘作为格
  • gqrx编译过程记录

    gqrx编译过程记录 目标 环境 编译 下载源代码 建立编译位置 修改CMakefile txt中的模块 编译安装 运行界面 没有更多 目标 在ubuntun 20 04桌面版编译gqrx 通过USRP 205mini实现收音机功能 环境
  • 【解决】docker容器怎么使用宿主机的IPv6地址

    在IPv4时代 我们对外访问都是端口映射 都没有公网IP 但是在IPv6时大家都有公网IP 可能需要容器地址和主机地址一致 可以在docker run时使用参数 network host 则此容器网络和宿主机一致 docker run ne
  • AQS详解

    AQS详解 文章目录 AQS详解 AQS简单介绍 AQS原理 AQS原理概览 AQS对资源的共享方式 AQS定义两种资源共享方式 Exclusive 独占 Share 共享 AQS底层使用了模板方法模式 Semaphore 信号量 Coun
  • 浅谈可重入锁

    一 可重入锁 递归锁 1 概念 同一个线程在外层方法获取锁的时候 再进入该线程的内层方法会自动获取锁 前提是 锁对象是同一个对象 不是因为之前已经获取过还没有释放而阻塞 2 java中的ReentrantLock和synchronied都是
  • 关于Gdi+和GdiplusStartup

    GDI 实际上是一组类的定义 封装了gdi 的几乎所有API 当然使用方法就要从这些 例子 里边寻找了 本文正是尝试用GDI 写一个纯SDK的程序 语言自然是我最喜欢的语言WIN32ASM 这个程序很简单 就是用GDI 画了一条直线 算是抛
  • HCIA-FusionCompute华为企业级虚拟化

    一 云计算 按需付费 集中资源对外提供服务 1 云本身没有资源 云是资源整合者 整合底层的所有计算机资源 cpu 内存 磁盘等 云计算是一种模型 它可以实现随时随地 随需应变地从可配置计算资源共享池中获取所需的资源 例如 网络 服务器 存储
  • BigDecimal 问题小结

    BigDecimal 加法 add 函数 乘法multiply 函数 除法divide 函数 绝对值abs 函数 减法subtract 函数 ROUND CEILING 向正无穷方向舍入 ROUND DOWN 向零方向舍入 ROUND FL
  • 【Redis】新增数据结构

    BitMap位图 Redis提供了Bitmaps这个 数据类型 可以实现对位的操作 1 Bitmaps本身不是一种数据类型 实际上它就是字符串 key value 但是它可以对字符串的位进行操作 2 Bitmaps单独提供了一套命令 所以在