本文介绍通过 redis 的 键空间消息(Redis Keyspace Notifications) 结合 Subscribe 完成延时任务。
相关概念
发布/订阅(publish/subscribe)模式
发布/订阅模式可以实现进程间的消息传递,“发布/订阅”模式包含两种角色:发布者和订阅者。订阅者可以订阅一个或多个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会受到此消息。
而在延时任务的场景中,延时任务的产生就相当于发布者,订阅者根据接收到的消息执行延时任务。
键空间消息
功能描述
Keyspace notifications is a feature available since 2.8.0. It allow clients to subscribe to Pub/Sub channels in order to receive events affecting the Redis data set in some way.
键空间消息允许客户端订阅“发布频道”或“订阅频道”,以便接收以某种方式影响Redis数据集的事件。具体的方式有(key指redis数据结构中的键):
- 所有影响给定key值的命令
- 所有接收LPUSH操作的key值
- 所有在database 0 中过期的key值
事件类型
键空间消息是通过给每一个影响Redis数据空间的操作发送两种不同类型的事件来实现的。
1 | PUBLISH __keyspace@0__:mykey del # 被称为Key-space notification |
当然,为了发送特定的子事件,我们也可以仅使用一种事件消息类型。
启用配置
启用该功能会消耗一些CPU,所以默认状态是关闭的。可以通过设置 redis.conf 中的 notify-keyspace-events 为下列组合值时即可启用特定的事件通知类型:对于延时任务而言,设定值为 Ex 足矣。
1 | K Keyspace events, published with __keyspace@<db>__ prefix. |
过期事件的时间
Redis通过两种方式设置有效的key过期:
- 当某个命令去访问该key却发现已经过期了
- 通过后台系统寻找过期的key,逐一以便收集从未访问过的key
上述两种方式都不保证产生过期事件的时间与key的生存时间恰好为0完全一致。从本质上说,过期事件的产生是Redis服务器删除key,而不是key的生存事件为0,所以产生时间差是在所难免的。
代码实现
创建key值并设置过期时间:Produce.php
1 | $redis = new \Redis(); |
延时任务执行脚本:Task.php
1 | <?php |
执行步骤
- Linux终端先执行
php Task.php开始监听 - 浏览器访问
Produce.php文件设置 key 和 过期时间 - 20s 后输出信息
1 | Pattern: __keyevent@15__:expired |