redis · 2022-01-27 0

Redis键空间通知(keyspace notifications)

一、概述

Redis键空间通知(keyspace notifications)是基于订阅/发布(Pub/Sub)机制。

二、事件类型

  1. keyspace事件
  2. keyevent事件

比如,在0号库,键myKey过期,会触发两个消息,等价于执行两个publish命令:

publish __keyspace@0__:myKey expired
publish __keyevent@0__:expired myKey

可以通过配置,使Redis仅发送某一类通知

三、配置

可以通过修改配置文件redis.conf,或者通过config set命令,设置notify-keyspace-events选项,来启用或关闭该功能

该选项的值为空字符串时,该功能禁用,选项值为非空字符串时,启用该功能,非空字符串由特定的多个字符组成,每个字符表示不同的意义:

  • K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布
  • E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布
  • g:一般性的,非特定类型的命令,比如del,expire,rename等
  • $:字符串特定命令
  • l:列表特定命令
  • s:集合特定命令
  • h:哈希特定命令
  • z:有序集合特定命令
  • x:过期事件,当某个键过期并删除时会产生该事件
  • e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件
  • A:g$lshzxe的别名,因此”AKE”意味着所有事件

例如:

设置键过期,发送keyspace事件和keyevent事件通知

config set notify-keyspace-events "xKE"

四、命令

  • DEL 命令为每个被删除的键产生一个 del 事件;
  • RENAME 产生两个事件:为源键产生一个 rename_from 事件,并为目标键产生一个 rename_to 事件;
  • EXPIRE命令,在设置键的过期时间时产生一个 expire事件;当键因过期而被删除时,产生一个 expired事件;
  • MSET 命令,为每个键产生一个 set 事件;

五、命令行使用键空间通知

1.配置通知

设置键过期,发送keyspace事件和keyevent事件通知

config set notify-keyspace-events "xKE"

2.栗子

keyspace事件订阅端:

psubscribe __keyspace@0__:mykey

keyevent事件订阅端:

psubscribe __keyevent@0__:expired

发布端:

10s 后myKey过期

setex myKey 10 "zhang san"

3.结果

keyspace事件订阅端结果:

1) "pmessage"
2) "__keyspace@0__:myKey"
3) "__keyspace@0__:myKey"
4) "expired

keyevent事件订阅端结果:

1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "myKey"

六、java使用键空间通知

pom 文件

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

1.配置通知

设置键过期,发送keyspace事件和keyevent事件通知

@Test
public void testConfigKeyspace() {
    Jedis jedis = new Jedis("localhost");
    jedis.configSet("notify-keyspace-events", "xKE");
}

2.栗子

回调类

public class Subscriber extends JedisPubSub {

    @Override
    public void onPMessage(String pattern, String channel, String message) {
        System.out.println(String.format("onPMessage: pattern %s, channel %s, message %s", pattern, channel, message));
    }

    @Override
    public void onPSubscribe(String pattern, int subscribedChannels) {
        System.out.println(String.format("onPSubscribe: pattern %s, subscribedChannels %s", pattern, subscribedChannels));
    }

    @Override
    public void onPUnsubscribe(String pattern, int subscribedChannels) {
        System.out.println(String.format("onPUnsubscribe: pattern %s, subscribedChannels %s", pattern, subscribedChannels));
    }

    // 收到消息会调用
    @Override
    public void onMessage(String channel, String message) {
        System.out.println(String.format("onMessage: channel %s, message %s", channel, message));
    }

    // 订阅了频道会调用
    @Override
    public void onSubscribe(String channel, int subscribedChannels) {
        System.out.println(String.format("onSubscribe: channel %s, subscribedChannels %d",
                channel, subscribedChannels));
    }

    // 取消订阅 会调用
    @Override
    public void onUnsubscribe(String channel, int subscribedChannels) {
        System.out.println(String.format("onUnsubscribe: channel %s, subscribedChannels %d",
                channel, subscribedChannels));
    }
}

keyspace事件订阅端:

@Test
public void testPsubscribeKeyspace() {
    Jedis jedis = new Jedis("localhost");
    jedis.psubscribe(new Subscriber(), "__keyspace@0__:myKey");
}

keyevent事件订阅端:

@Test
public void testPsubscribeKeyevent() {
    Jedis jedis = new Jedis("localhost");
    jedis.psubscribe(new Subscriber(), "__keyevent@0__:expired");
}

发布端:
10s 后myKey过期

@Test
public void testExpire() {
    Jedis jedis = new Jedis("localhost");
    jedis.set("myKey", "zhang san");
    jedis.expire("myKey", 10);
}

3.结果

keyspace事件订阅端结果:

onPSubscribe: pattern __keyspace@0__:myKey, subscribedChannels 1
onPMessage: pattern __keyspace@0__:myKey, channel __keyspace@0__:myKey, message expired

keyevent事件订阅端结果:

onPSubscribe: pattern __keyevent@0__:expired, subscribedChannels 1
onPMessage: pattern __keyevent@0__:expired, channel __keyevent@0__:expired, message myKey