前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis 键空间通知 Keyspace Notification 事件订阅

Redis 键空间通知 Keyspace Notification 事件订阅

作者头像
Tinywan
发布2024-07-05 12:39:24
1010
发布2024-07-05 12:39:24
举报
文章被收录于专栏:开源技术小栈

概述

本文所说的定时任务或者说计划任务并不是很多人想象中的那样,比如说每天凌晨三点自动运行起来跑一个脚本。这种都已经烂大街了,随便一个 Crontab 就能搞定了。

这里所说的定时任务可以说是计时器任务,比如说用户触发了某个动作,那么从这个点开始过二十四小时我们要对这个动作做点什么。那么如果有 1000 个用户触发了这个动作,就会有 1000 个定时任务。于是这就不是 Cron 范畴里面的内容了。

举个最简单的例子,一个用户推荐了另一个用户,我们定一个二十四小时之后的任务,看看被推荐的用户有没有来注册,如果没注册就给他搞一条短信过去。

功能概览

键空间通知使得客户端可以通过订阅频道或模式, 来接收那些以某种方式改动了 Redis 数据集的事件。事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发, 因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下, 直接使用键空间通知功能。

键空间消息

在 Redis 的 2.8.0 版本之后,其推出了一个新的特性——键空间消息(Redis Keyspace Notifications),它配合 2.0.0 版本之后的 SUBSCRIBE 就能完成这个定时任务的操作了,不过定时的单位是秒。

Publish / Subscribe

Redis 在 2.0.0 之后推出了 Pub / Sub 的指令,大致就是说一边给 Redis 的特定频道发送消息,另一边从 Redis 的特定频道取值——形成了一个简易的消息队列。

Redis Keyspace Notifications

在 Redis 里面有一些事件,比如键到期、键被删除等。然后我们可以通过配置一些东西来让 Redis 一旦触发这些事件的时候就往特定的 Channel 推一条消息。

大致的流程就是我们给 Redis 的某一个 db 设置过期事件,使其键一旦过期就会往特定频道推消息,我在自己的客户端这边就一直消费这个频道就好了。

以后一来一条定时任务,我们就把这个任务状态压缩成一个键,并且过期时间为距这个任务执行的时间差。那么当键一旦到期,就到了任务该执行的时间,Redis 自然会把过期消息推去,我们的客户端就能接收到了。这样一来就起到了定时任务的作用。

配置

因为开启键空间通知功能需要消耗一些 CPU , 所以在默认配置下, 该功能处于关闭状态。可以通过修改 redis.conf 文件, 或者直接使用 CONFIG SET 命令来开启或关闭键空间通知功能。

  • notify-keyspace-events选项的参数为空字符串时,功能关闭。
  • 当参数不是空字符串时,功能开启。

notify-keyspace-events 的参数可以是以下字符的任意组合, 它指定了服务器该发送哪些类型的通知

输入的参数中至少要有一个 K 或者 E , 否则的话, 不管其余的参数是什么, 都不会有任何通知被分发。举个例子, 如果只想订阅键空间中和列表相关的通知, 那么参数就应该设为 Kl , 诸如此类。

具体配置

首先找到redis.conf配置文件,打开文件,查找notify-keyspace-events,将前面的#去掉即可。

“注意:这里配置的是notify-keyspace-eventsEx参数,即说明,当键过期的时候会触发通知,如果只需要哈希命令键触发通知则可以设置为notify-keyspace-events Eh。 ”

配置完成重启redis-server即可

使用

命令行

开启一个终端,redis-cli 进入 redis 。开始订阅所有操作,等待接收消息。

代码语言:javascript
复制
127.0.0.1:6379> psubscribe __keyevent@0__:expired  
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1

再开启一个终端,redis-cli 进入 redis,新增一个 20秒过期的键

代码语言:javascript
复制
127.0.0.1:6379> SETEX username 30 Tinywan        
OK
127.0.0.1:6379> get username
"Tinywan"
127.0.0.1:6379> TTL username
(integer) 25
127.0.0.1:6379> 

另外一边执行了阻塞订阅操作后的终端,20秒过期后有如下信息输出:

代码语言:javascript
复制
127.0.0.1:6379> psubscribe __keyevent@0__:expired  
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "username"

输出以上信息,说明对过期Key信息的订阅是成功的。

发布订阅截图

PHP语言代码

Redis实例类RedisInstance

代码语言:javascript
复制
<?php
/**
 * @desc RedisInstance.php 描述信息
 * @author Tinywan(ShaoBo Wan)
 * @date 2024/6/26 21:36
 */
declare(strict_types=1);

class RedisInstance
{
    private Redis $redis;

    /**
     * @param string $host
     * @param int $port
     * @throws RedisException
     */
    public function __construct(string $host = '127.0.0.1', int $port = 6379)
    {
        $this->redis = new Redis();
        $this->redis->connect($host, $port);
    }

    /**
     * @desc expire
     * @param null $key
     * @param int $time
     * @return bool|Redis
     * @throws RedisException
     * @author Tinywan(ShaoBo Wan)
     */
    public function expire($key = null, int $time = 0)
    {
        return $this->redis->expire($key, $time);
    }

    /**
     * @desc psubscribe
     * @param $callback
     * @param array $patterns
     * @throws RedisException
     * @author Tinywan(ShaoBo Wan)
     */
    public function psubscribe($callback, array $patterns = [])
    {
        $this->redis->psubscribe($patterns, $callback);
    }

    /**
     * @desc setOption
     * @author Tinywan(ShaoBo Wan)
     */
    public function setOption()
    {
        $this->redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
    }
}

订阅文件psubscribe.php

代码语言:javascript
复制
<?php
/**
 * @desc psubscribe.php 描述信息
 * @author Tinywan(ShaoBo Wan)
 * @date 2024/6/26 21:39
 */

require '../vendor/autoload.php';

$redis = new \RedisInstance('dnmp-redis');
$redis->setOption();
$redis->psubscribe(function ($redis, $pattern, $channel, $msg){
    echo 'Pattern:' . $pattern .PHP_EOL;
    echo 'Channel:' . $channel .PHP_EOL;
    echo 'Message:' . $msg .PHP_EOL;
}, ['__keyevent@0__:expired']);

运行psubscribe.php 观察订阅状态

代码语言:javascript
复制
# php psubscribe.php

Pattern:__keyevent@0__:expired
Channel:__keyevent@0__:expired
Message:username

Pattern:__keyevent@0__:expired
Channel:__keyevent@0__:expired
Message:username2

Pattern:__keyevent@0__:expired
Channel:__keyevent@0__:expired
Message:username3

发布事件

代码语言:javascript
复制
127.0.0.1:6379> SETEX username 3 Tinywan
OK
127.0.0.1:6379> SETEX username2 5 Tinywan
OK
127.0.0.1:6379> SETEX username3 5 Tinywan

小结结

通过以上步骤,成功地实现了Redis键空间通知使用。首先配置Redis服务器,开启键空间通知功能,然后通过命令行和编写客户端代码来接收并处理通知。这个功能可以帮助我们实时地获取数据库操作的变化,非常适用于需要实时更新数据的应用程序。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 功能概览
  • 键空间消息
  • 配置
    • 具体配置
    • 使用
      • 命令行
        • PHP语言代码
        • 小结结
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档