Redis十大数据模型(下)

Redis位域(bitfield)

能干嘛

位域修改、溢出控制

一句话

将一个redis字符串看作是一个由二进制位组成的数组并能对变长位宽和任意没有字节对齐的指定整型位域进行寻址和修改

命令代码实操

Ascii码表:https://ascii.org.cn

1.BITFIELD key [GET type offset]

2.BITFIELD key set type offstet value

3.BITFIELD key [INCRBY type offset increment]

如果偏移量后面的值发生溢出(大于127),redis对此也有对应的溢出控制,默认情况下,INCRBY使用WRAP参数

4.溢出控制 OVERFLOW [WRAP|SAT|FAIL]

WRAP:使用回绕(wrap around)方法处理有符号整数和无符号整数溢出情况

fail:命令将拒绝执行那些会导致上溢或者下溢情况出现的计算,并向用户返回空值表示计算未被执行

Redis位图(bitmap)

一句话:由0和1状态表现的二进制位的bit数组

看需求:

  1. 用户是否登陆过Y、N,比如软件的每日签到功能
  2. 电影、广告是否被点击播放过
  3. 钉钉打卡上下班,签到统计

是什么?

说明:$\textcolor{red}{用String类型作为底层数据结构实现的一种统计二值状态的数据类型}$

位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。

Bitmap支持的最大位数是2^32位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(2^32=4294967296)

能干嘛?

用于状态统计,Y、N类似AtomicBoolean

基本命令

setbit 键偏移位 只能零或者1

Bitmap的偏移量从零开始计算的

2.getbit key offset

获取键偏移位的值

3.strlen key

统计字节数占用多少

不是字符串长度而是占据几个字节,超过8位后自己按照8位一组一byte再扩容

4.bitcount key [start end [byte|bit]]

全部键里面包含有1的有多少个

5.bitop operation(AND|OR|XOR|NOT) destkey key [key ...]

案例:连续2天都签到的用户数量

假如某个网站或者系统,它的用户有1000W,我们可以使用redis的HASH结构和bitmap结构做个用户id和位置的映射

以下链接是6~10的详解

Redis之十大类型(三)(下)_晓风残月 redis-CSDN博客

6.redis地理空间(GEO)

Redis GEO主要用于存储地理位置信息,并对存储的信息进行操作,包括:

添加地理位置的坐标。

获取地理位置的坐标。

计算两个位置之间的距离。

根据用户给定的经纬度坐标来获取指定范围内的地址位置集合。

7.redis基数统计(HyperLogLog)

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

在Redis里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

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

8.redis位图(bitmap)

由0和1状态表现的二进制位的bit数组

9.redis位域(bitfield)

通过bitfield命令可以一次性操作多个$\textcolor{red}{比特位域(指的是连续的多个比特位)}$,它会执行一系列操作并返回一个响应数组,这个数组中的元素对应参数列表中的相应的执行结果。

说白了就是通过bitfield命令我们可以一次性对多个比特位域进行操作。

10.redis流(Stream)

Redis Stream是Redis5.0版本新增加的数据结构。

Redis Stream主要用于消息队列(MQ,Message Queue),Redis本身就是一个Redis发布订阅(pub/sub)来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis宕机等,消息就会被丢弃。

简单来说发布订阅(pub/sub)可以分发消息,但无法记录历史消息。

而Redis Stream提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

redis常见数据类型操作命令

官网英文: Commands | Docs

中文:http://www.redis.cn/commands.html

Redis基数统计(HyperLogLog)

看需求:

用户搜索网站关键词的数量

统计用户每天搜索不同词条个数

统计某个网站的UV、统计某个文章的UV

什么是UV?

Unique Visitor,独立访客,一般理解为客户端IP,需要去重考虑

是什么

去重复统计功能的基数估计算法-就是HyperLogLog

Redis在2.8.9版本添加了HyperLogLog 结构。
Redis HyperLogLog是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在Redis里面,每个 HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费
内存就越多的集合形成鲜明对比。
但是,因为HyperLogLog只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素。

基数:是一种数据集,去重复后的真实个数

(全集)={2,4,6,8,77,39,4,8,10}
去掉重复的内容
基数={2,4,6,8,77,39,10} = 7

基数统计:用于统计一个集合中不重复的元素个数,就是对集合去重复后剩余元素的计算。

一句话:去重脱水后的真实数据

基本命令:

Redis地理空间(GEO)

简介:

移动互联网时代LBS应用越来越多,交友软件中附近的小姐姐、外卖软件中附近的美食店铺、高德地图附近的核酸检查点等等,那这种附近各种形形色色的XXX地址位置选择是如何实现的? 地球上的地理位置是使用二维的经纬度表示,经度范围(-180,180],纬度范围(-90,90],只要我们确定一个点的经纬度就可以取得他在地球的位置。 例如滴滴打车,最直观的操作就是实时记录更新各个车的位置, 然后当我们要找车时,在数据库中查找距离我们(坐标x0,y0)附近r公里范围内部的车辆 使用如下SQL即可:

select taxi from position where x0-r< X < x0 + r and y0-r< y < y0+r

但是这样会有什么问题呢? 1.查询性能问题,如果并发高,数据量大这种查询是要搞垮数据库的 2.这个查询的是一个矩形访问,而不是以我为中心r公里为半径的圆形访问。 3.精准度的问题,我们知道地球不是平面坐标系,而是一个圆球,这种矩形计算在长距离计算时会有很大误差

原理

redis在3.2版本以后增加了地址位置的处理

命令

1.GEOADD key longitude latitude member [longitude latitude member]

多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的key中

命令:GEOADD city 116.403963 39.915119 "天安门" 116.403414 39.924091 "故宫" 116.024067 40.362639 "长城"

geo类型实际上是zset,可以使用zset相关的命令对其进行遍历,如果遍历出现中文乱码可以使用如下命令:redis-cli --raw

2.GEOPOS key member [member]

从键里面返回所有指定名称(member )元素的位置(经度和纬度),不存在返回nil

GEOPOS city 天安门 故宫 长城

3.GEODIST key member1 member2 [M|KM|FT|MI]

返回两个给定位置之间的距离

m-米

km-千米

ft-英寸

mi-英里

4.GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]

以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有元素位置

WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。 WITHCOORD: 将位置元素的经度和维度也一并返回。 WITHHASH:以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试,实际中的作用并不大 COUNT 限定返回的记录数。

5.GEORADIUSBYMEMBER

跟GEORADIUS类似

6.GEOHASH

返回一个或多个位置元素的GEOhash表示

geohash 算法生成的base32编码值,3维变2维变1维

Redis流(Stream)

是什么

Redis5.0 之前的痛点,Redis消息队列的2种方案:

  1. List实现消息队列,List实现方式其实就是点对点的模式
  2. Pub/Sub

Redis5.0版本新增了一个更强大的数据结构---Stream

一句话:Stream流就是Redis版的MQ消息中间件+阻塞队列

能干嘛

实现消息队列,它支持消息的持久化、支持自动生成全局唯一ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠

底层结构和原理说明

一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的ID和对应的内容

基本命令理论简介

队列相关指令

消费组相关指令

XINFO GROUPS 打印消费组的详细信息

XINFO STREAM 打印stream的详细信息

四个特殊符号

- +

最小和最大可能出现的Id

$

$表示只消费新的消息,当前流中最大的Id,可用于将要到来的信息

>

用于XREADGROUP命令,表示迄今还没有发送给组中使用者的信息,会更新消费者组的最后Id

*

用于XADD命令,让系统自动生成Id

基本命令代码实操

队列相关命令

1.XADD

添加消息到队列末尾,消息ID必须要比上一个ID大,默认用星号表示自动生成ID;* 用于XADD命令中,让系统自动生成ID;

XADD用于向Stream队列中添加消息,如果指定的Stream队列不存在,则该命令执行时会新建一个Stream队列

生成的消息ID,有两部分组成,毫秒时间戳-该毫秒内产生的第一条消息

// * 表示服务器自动生成MessageID(类似MySQL里面主键auto_increment),后面顺序跟着一堆业务key/value

信息条目指的是序列号,在相同的毫秒下序列号从0开始递增,序列号是64位长度,理论上在同一毫秒内生成的数据量无法到达这个级别,因此不用担心序列号会不够用。milisecondsTime指的是Redis节点服务器的本地时间,如果存在当前的毫秒时间截比以前已经存在的数据的时间戳小的话(本地时间钟后跳),那么系统将会采用以前相同的毫秒创建新的ID,也即redis 在增加信息条目时会检查当前 id 与上一条目的 id,自动纠正错误的情况,一定要保证后面的 id 比前面大,.个流中信息条目的ID必须是单调增的,这是流的基础。

客户端显示传入规则:
Redis对于ID有强制要求,格式必须是时间戳-自增Id这样的方式,且后续ID不能小于前一个ID

Stream的消息内容,也就是图中的Messaget它的结构类似Hash结构,以kev-value的形式存在

2.XRANGE key start end [COUNT count]

用于获取消息列表(可以指定范围),忽略删除的消息

start 表示开始值,-代表最小值

end 表示结束值,+代表最大值

count 表示最多获取多少个值

3.XREVRANGE key end start [COUNT count]

根据ID降序输出

4.XDEL key id [id ...]

5.XLEN key

6.XTRIM key MAXLEN|MINID

用于对Stream的长度进行截取,如超长会进行截取

MAXLEN 允许的最大长度,对流进行修剪限制长度

MINID 允许的最小id,从某个id值开始比该id值小的将会被抛弃

7.XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

可以读取多个key

用于获取消息(阻塞/非阻塞)

只会返回大于指定ID的消息,COUNT最多读取多少条消息;BLOCK是否以阻塞的方式读取消息,默认不阻塞,如果milliseconds设置为0,表示永远阻塞

非阻塞

  • $表特殊ID,表示以当前Stream已经存储的最大的ID作为最后一个ID,当前Stream中不存在大于当前最大ID的消息,因此此时返回nil
  • 0-0代表从最小的ID开始获取Stream中的消息,当不指定count,将会返回Stream中的所有消息,注意也可以使用0 (00/000也都是可以的)

阻塞

小总结(类似Java里面的阻塞队列)

Stream的基础方法,使用XADD存入消息和XREAD循环阻塞读取消息的方式可以实现简易版的消息队列


消费组相关指令

1.XGROUP CREATE key group id|$

用于创建消费组

xgroup create mystream group $

xgroup create mystream groupB 0

$表示从Stream尾部开始消费

0表示从Stream头部开始消费

创建消费组的时候必须指定ID,ID为0表示从头开始消费,为$表示只消费新消息

''

2.XREADGROUP GROUP group [COUNT count] [BLOCK milliseconds] STREAMS key id

">",表示从第一条尚未被消费的消息开始读取

消费组groupA内的消费者consumer1从mystream消息队列中读取所有消息

但是,不同消费组的消费者可以消费同一条消息

消费组的目的?

让组内的多个消费者共同分担读取消息,所以,我们通常会让每个消费者读取部分消息,从而实现消息读取负载在多个消费者间是均衡分部的

重点问题

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

Streams 会自动使用内部队列(也称为 PENDING List)留存消费组里每个消费者读取的消息保底措施,直到消费者使用 XACK命令通知 Streams"消息已经处理完成”。 消费确认增加了消息的可靠性,一般在业务处理完成之后,需要执行 XACK 命令确认消息已经被消费完成

3.XPENDING

查询每个消费组内所有消费组$\textcolor{red}{[已读取、但尚未确认]}$的消息

查看某个消费组具体读取了那些数据

4.XACK key group id [id...]

向消息队列确认消息处理已完成

XINFO 用于打印Stream\Consumer\Group的详细信息

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值