(二)Redis丰富的功能

文章介绍了Redis的多种高级特性,包括键的过期时间设置及其应用,发布订阅消息机制,pipeline优化网络通信,原子性事务与Lua脚本的使用,Bitmaps位图操作,HyperLogLog基数估算,GEO地理位置功能,Stream消息队列以及布隆过滤器的数据去重策略。这些特性扩展了Redis的基础数据类型,增强了其在缓存、统计、定位等场景的应用能力。
摘要由CSDN通过智能技术生成

目录

1. 键过期

2. 发布订阅

3.pipeline(管道)

4.事务和Lua

5. Bitmaps (位图)

6. HyperLogLog

7. GEO

8. Stream

9. 布隆过滤器


前面提到了Redis的五个基本的数据类型,在此基础有演变了不少类型。但是这篇要聊一下Redis的丰富的功能。

如下:

  1. 键过期

  2. 发布订阅

  3. pipeline(管道)

  4. 事务和lua

  5. Bitmaps (位图)

  6. HyperLogLog

  7. GEO

  8. Stream

  9. 布隆过滤器

1. 键过期

Redis支持对键添加过期时间, 当超过过期时间后, 会自动删除键

常用在缓存、session共享、分布式锁等应用场景

设置过期时间:

expire key seconds //键在seconds秒后过期

expireat key timestamp //键在秒级时间戳timestamp后过期

可通过ttl和pttl查看剩余过期时间

ttl key //返回秒级剩余过期时间
pttl key //返回毫秒级剩余过期时间

有3种返回值:

  • 大于等于0的整数: 键剩余的过期时间

  • -1: 键没有设置过期时间

  • -2: 键不存在

2. 发布订阅

​ Redis提供了基于“发布/订阅”模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道(channel)发布消息, 订阅该频道的每个客户端都可以收到该消息 。

发布消息:

publish channel message

订阅消息:

订阅一个或多个消息

subscribe channel [channel ...]

缺点:

  • 消息不会持久化

  • 新的订阅之前的消息及重新订阅期间的消息无法接收。

3.pipeline(管道)

Redis客户端执行一条命令的过程分为:发送命令、命令排队、命令执行、返回结果。

整个过程的耗时时间称为RTT(往返时间)

虽然Redis提供了部分批量操作命令,有效节约了RTT,但是大部分命令还是不支持批量操作。

Redis提供了pipeline(管道)改善这个问题。pipeline(管道)能将一组命令进行组装通过一次RTT传输给Redis,再将这组命令的返回结果按顺序返回客户端。

原生批量命令与Pipeline对比

可以使用Pipeline模拟出批量操作的效果, 但是在使用时要注意它与原生批量命令的区别, 具体包含以下几点:

  • 原生批量命令是原子的, Pipeline是非原子的。

  • 原生批量命令是一个命令对应多个key, Pipeline支持多个命令。

  • 原生批量命令是Redis服务端支持实现的, 而Pipeline需要服务端和客户端的共同实现。

注意:

每次Pipeline组装命令不能太多,避免一次组装Pipeline数据量过大,增加客户端等待时间;另一个是会造成网络阻塞。

4.事务和Lua

​ 为了保证多条命令组合的原子性, Redis提供了简单的事务功能以及集成Lua脚本来解决这个问题。

4.1 事务

Redis提供了简单的事务功能, 将一组需要一起执行的命令放到multi和exec两个命令之间。 multi命令代表事务开始, exec命令代表事务结束, 它们之间的命令是原子顺序执行的。

//开启事务
127.0.0.1:6379> multi
OK
//集合中添加数据,返回QUEUED代表未真正执行,暂保存在redis中
127.0.0.1:6379> sadd user:a:a1 user:b
QUEUED
127.0.0.1:6379> sadd user:b:b1 user:a
QUEUED

另一个客户端中查看集合中成员是否存在,返回为0:不存在。数据为真正添加

127.0.0.1:6379> sismember user:a:a1 user:b
(integer) 0

停止事务:

127.0.0.1:6379> discard
OK
127.0.0.1:6379> sismember user:a:a1 user:b
(integer) 0

两个个客户端中查看集合中成员是否存在,都返回为0:不存在。

127.0.0.1:6379> sismember user:a:a1 user:b
(integer) 0

提交事务:

127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> sismember user:a:a1 user:b
(integer) 1

另一个客户端中查看集合中成员是否存在,返回为1:成员存在。

127.0.0.1:6379> sismember user:a:a1 user:b
(integer) 1

命令错误时,Redis的处理机制:

  • 命令错误:语法错误,如:set写成了sett等,事务回退,命令未真正执行

  • 运行时错误:语法正常,但命令使用不当,事务继续执行

4.2 Lua

Redis将Lua作为脚本语言可帮助开发者定制自己的Redis命令 。

Lua脚本功能带来如下三个好处:

  • Lua脚本在Redis中是原子执行的, 执行过程中间不会插入其他命令。

  • Lua脚本可以帮助开发和运维人员创造出自己定制的命令, 并可以将这些命令常驻在Redis内存中, 实现复用的效果。

  • Lua脚本可以将多条命令一次性打包, 有效地减少网络开销。

比如给一个列表中的所有元素加1,并保证原子执行,就可以通过Lua实现。

示例:列表中所有元素及元素的值

127.0.0.1:6379> lrange user:list 0 -1
1) "user:d:userId"
2) "user:c:userId"
3) "user:b:userId"
4) "user:a:userId"
127.0.0.1:6379> mget user:a:userId user:b:userId user:c:userId user:d:userId
1) "100"
2) "101"
3) "102"
4) "103"

使用Lua给一个列表中的所有元素加1脚本:lrange_inc.lua

local mylist = redis.call("lrange", KEYS[1], 0, -1)
local count = 0
for index,key in ipairs(mylist)
do
 redis.call("incr",key)
 count = count + 1
end
return count

执行脚本:

redis-cli.exe --eval lrange_inc.lua user:list
(integer) 4

查看执行后的结果:

127.0.0.1:6379> mget user:a:userId user:b:userId user:c:userId user:d:userId
1) "101"
2) "102"
3) "103"
4) "104"

可以看到已经执行成功。

5. Bitmaps (位图)

许多开发语言都提供了操作位的功能, 合理地使用位能够有效地提高内存使用率和开发效率。

Redis提供了Bitmaps可以实现对位的操作。

Bitmaps属于字符串类型的拓展,能对字符串进行位操作,并且有单独的操作命令。

set m1 a
setbit  m1 1 0
setbit m1 2 1
get m1 
/* 1 2 代表的a的二进制位的修改
a 对应的ASCII码是97,转换为二进制数据是01100001
b 对应的ASCII码是98,转换为二进制数据是01100010

因为bit非常节省空间(1 MB=8388608 bit),可以用来做大数据量的统计。

适用场景:用户的签到,在线用户统计,留存用户统计等

setbit onlineusers 11 
setbit onlineusers 12 
setbit onlineusers 13

支持按位与、按位或等等操作

BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。       
BITOPORdestkeykey[key...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。 
BITOPXORdestkeykey[key...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。 
BITOPNOTdestkeykey ,对给定 key 求逻辑非,并将结果保存到 destkey 。

计算出3天内都在线的用户

BITOP "AND" "3_days_both_online_users" "day_1_online_users" "day_2_online_users" "day_3_online_users"

6. HyperLogLog

​ HyperLogLog也是字符串类型的拓展,是一种基数算法,通过HyperLogLog可以利用极小的内存空间完成独立总数的统计, 数据集可以是IP、 Email、 ID等。

HyperLogLog提供了3个命令:pfadd、 pfcount、 pfmerge。

HyperLogLog内存占用量非常小, 但是存在错误率, 开发者在进行数据结构选型时只需要确认如下两条即可:

  • 只为了计算独立总数, 不需要获取单条数据。

  • 可以容忍一定误差率, 毕竟HyperLogLog在内存的占用量上有很大的优势

127.0.0.1:6379> pfadd 2023_02_03:unique:ids "pf-1" "pf-2" "pf-3" "pf-4"
(integer) 1
127.0.0.1:6379> pfcount 2023_02_03:unique:ids
(integer) 4
127.0.0.1:6379> pfadd 2023_02_03:unique:ids "pf-1" "pf-2" "pf-3" "pf-5"
(integer) 1
127.0.0.1:6379> pfcount 2023_02_03:unique:ids
(integer) 5

计算02和03总数

127.0.0.1:6379> pfadd 2023_02_02:unique:ids "pf-1" "pf-2" "pf-3" "pf-6" "pf-7"
(integer) 1
127.0.0.1:6379> pfmerge  2023_02_02_03:unique:ids 2023_02_03:unique:ids 2023_02_02:unique:ids
OK
127.0.0.1:6379> pfcount 2023_02_02_03:unique:ids
(integer) 7

7. GEO

Redis3.2版本提供了GEO(地理信息定位) 功能, 支持存储地理位置信息用来实现诸如附近位置、 摇一摇这类依赖于地理位置信息的功能。

//添加坐标
127.0.0.1:6379> geoadd user:local 114.325916 30.619074 zhangsan
(integer) 1
127.0.0.1:6379> geoadd user:local 114.32615 30.619369 lisi
(integer) 1
127.0.0.1:6379> geoadd user:local 114.324335 30.620239 wanger
(integer) 1
127.0.0.1:6379> geoadd user:local 113.828022 30.271863 mazi
(integer) 1
//查询用户坐标
127.0.0.1:6379> geopos user:local lisi
1) 1) "114.326152503490448"
   2) "30.61936950414612824"
127.0.0.1:6379> geopos user:local zhangsan
1) 1) "114.32591646909713745"
   2) "30.619072941770483"
127.0.0.1:6379> geopos user:local mazi
1) 1) "113.82802337408065796"
   2) "30.27186176792191219"
//计算两坐标之间的距离
127.0.0.1:6379> geodist user:local zhagnsan lisi
(nil)
127.0.0.1:6379> geodist user:local zhangsan lisi
"39.9810"

8. Stream

​ 在Redis5.0之后,新增了一种数据结构Stream,是一个新的强大的支持多播的可持久化的消息队列 。

Stream中的每个消息都由以下两部分组成。

  • 每个消息有唯一的消息ID,消息ID严格递增。

  • 消息内容由多个field-value对组成 。

xadd Stream名称 *代表ID由Redis自动生成,name mystream1 age 18,消息内容的键值对
xadd mystream * name mystream1 age 18

​ 生产者负责向消息队列中生产消息,消费者消费某个消息流。消费者可以归属某个消费组,也可以不归属任何消费组。当消费者不归属于任何消费组时,该消费者可以消费消息队列中的任何消息。

消费组是Stream的一个重要概念,具有以下特点。

  • 每个消费组通过组名称唯一标识,每个消费组都可以消费该消息队列的全部消息,多个消费组之间相互独立。

  • 每个消费组可以有多个消费者,消费者通过名称唯一标识,消费者之间的关系是竞争关系,也就是说一个消息只能由该组的一个成员消费。

  • 组内成员消费消息后需要确认,每个消息组都有一个待确认消息队列(pending entry list,pel),用以维护该消费组已经消费但没有确认的消息。

  • 消费组中的每个成员也有一个待确认消息队列,维护着该消费者已经消费尚未确认的消息。

相比发布/订阅来说,

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

  2. Redis Stream 提供了一个定长 Stream 功能,避免消息堆积,造成缓冲区溢出。

具体可参考文章:Redis消息队列——Redis Stream

9. 布隆过滤器

​ 布隆过滤器是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

具体原理可参考文章:Redis布隆过滤器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值