为什么要用键空间通知
场景 | Crontab | 键空间通知(Redis Keyspace Notification) |
---|---|---|
一个30min定时提醒事项 | 每一分钟轮询系统,查询到时间没有,有则向系统发送通知 | 设置30min后过期并向系统发送通知 |
用户触发24h后发推送 | 记录触发事件,每一小时计算差值是否达到24h,有则向系统发送通知 | 设置24h后过期并向系统发送通知 |
商品下单0.5h内不支付就撤单 | 记录开始时间,每一分钟查询整个数据库把未支付且时间超过半小时的单改状态 | 设置30min后过期并向系统发送通知。订单支付成功时触发退出redis过期队列 |
可以看到,有一些场景下,redis的键空间通知对比Crontab优势是,把颗粒度从整个系统下降到每一个事件。
Crontab因为不能定点每一个事件,所以每一次都要去查整个数据库去筛选事件,而键空间通知则是需要处理的事件自己在倒数事件,到点了就给系统发通知。这种颗粒度的下降,能够在编码的时候大大降低开发量,因为有的时候写出一个符合筛选条件的Crontab命令还是很麻烦的。
键空间通知
介绍
键空间通知功能,即Keyspace notification,是通过Redis的订阅与发布功能(Pub/Sub)来实现的,使得客户端通过订阅频道来收集一些Redis修改事件。
Redis在2.8.0版本及其以上版本才支持键空间通知(Keyspace Notification)功能。
那么收集的Redis修改事件举个例子:
- 所有修改键的命令
- 所有接收到LPUSH命令的键
- 0号数据库中所有已过期的键
需要注意的是:
- 键空间通知依赖的订阅与发布功能具有即发即忘(fire and forget)的特性,是不可靠的,所以在订阅与发布功能处于客户端断开连接,或者稍后重连,那么在失联这段时间的所有数据事件都会丢失。
特性
所有的 Redis 数据操作都会发送2种类型的事件。
举个例子,对0号数据库中一个key为mykey的键进行DEL(删除)操作,那么相当于执行了以下2个命令
1 | PUBLISH __keyspace@0__:mykey del |
第一个频道**keyspace@0:mykey,是在监听0号数据库中,键值为mykey的所有修改事件,包括这里的del命令。
第二个频道keyevent@0:del**,是在监听0号数据库中,所有执行del命令的键,包括这里的mykey键位。
以keyspace为前缀的频道,叫做键空间通知(Key-space notification),这个频道订阅者将收到被执行事件的名字,上面例子就是del。
以keyevent为前缀的频道,叫做键事件通知(Key-event notification),这个频道订阅者将收到被执行事件的键的名字,上面例子就是mykey。
配置
默认配置下,键空间通知功能因为会消耗一些CPU性能而被禁用,需要手动开启。
可以再redis.conf中的notify-keyspace-events
中开启,或者使用CONFIG SET
命令。
如果这个参数为空,那么功能关闭,否则开启。
参数如下
1 | K 键空间通知(Keyspace events),通过**__keyspace@<db>__**前缀来分发信息 |
需要注意,参数可以随机组合配对,但是一定要有一个K或者E,不然就收不到任何一个事件的分发。
使用键空间通知来实现延迟任务
举个例子,用户点击拍下物品,触发后向Redis写入过期时间为30分钟的名为「order_009394」的key。那么30分钟后这个key过期,我们的监听客户端捕获到这个key,并通过key知道了具体订单ID做下一步的逻辑操作,如作废订单等等。
以下流程以PHP代码作为演示。
前期准备
- Redis开启了键空间通知功能,配置了参数
Ex
(捕获过期事件). - PHP安装了扩展PHP-Redis
设置一个监听客户端
- 初始化一个Redis对象
- 订阅**keyevent@0:expired频道,即监听0号数据库中过期事件的键事件通知**.(不了解的可以往上翻了解命令的含义)
- 设置回掉后的逻辑操作,这里是直接输出传入的参数。(这个psubscribe函数的回调是预设好的4个参数,你可以输出看看结果分别是什么)
1 |
|
模拟一个任务写入
- 初始化一个Redis对象
- 往Redis推入一个有过期时间TTL的键值
1 |
|
观察监听客户端的结果
得到如图下结果
额外注意
Redis通过两种方式来删除一个过期的key:
- 访问key的时候发现其过期了,将其删除
- 为了删除一些再也不会被访问的过期键,后台会自动逐步增量的寻找过期的键。
所以过期事件并不完全等于TTL时间结束就会触发,因为过期事件是Redis清除key的时候才会触发。