从 Redis 2.8.0 开始支持键空间消息提醒(keyspace notification)和 发布/订阅模式功能。通过键空间消息提醒功能允许客户端通过订阅指定信道获取 Redis 数据变化的能力。由此 你会想到什么?如果 某个Redis实例没有不支持 psync 功能,则可以通过 键空间消息提醒 来获取Redis数据的变化,以此获取增量数据。-- 敲黑板,这里是 数据迁移工具的 基础原理。
注意,键空间消息提醒并不可靠,它不会对订阅端是否接收到消息进行确认。如果某个订阅的客户端断开重连,在此期间发生的数据变更事件将无法再次获得,一直向前增量。所以基于此功能开发的数据同步工具,需要校验。
默认 Redis 并未开启键空间消息提醒功能, 通过设置 notify-keyspace-events
参数的值进行开启,例如:
redis> CONFIG GET notify-keyspace-events
1) "notify-keyspace-events"
2) ""
redis> CONFIG SET notify-keyspace-events KEA
OK
redis> CONFIG GET notify-keyspace-events
1) "notify-keyspace-events"
2) "AKE"
在上述示例中将 notify-keyspace-events 配置为 KEA,代表除未命中外的所有事件。其中,K与E代表事件的两种类型——Keyspace与Keyevent。
Keyspace代表与事件名称相关的消息,例如订阅对指定键进行的操作事件; Keyevent代表与键名称相关的消息,例如订阅发生键过期事件的相关键名称。
关于更多的notify-keyspace-events配置,可参考下面的描述:
K 键空间事件,以__keyspace@<db>__前缀发布。
E 键事件事件,以__keyevent@<db>__前缀发布。
g 通用命令(非类型特定),如DEL,EXPIRE,RENAME等等
$ 字符串命令
l 列表命令
s 集合命令
h 哈希命令
z 有序集合命令
x 过期事件(每次键到期时生成的事件)
e 被驱逐的事件(当一个键由于达到最大内存而被驱逐时产生的事件)
A g$lshzxe的别名,因此字符串AKE表示所有的事件。
订阅的信道的格式为 @: 三个属性分别为:
tpye 事件类型(keyspace或keyevent)
db 数据库(例如数据库0)
event 事件(例如expired)
键空间通知功能为每一个影响 Redis 数据空间的操作发送两个不同类型的事件。例如,在数据库0中名为 keyname 的键上执行 SET 操作,将触发两条消息的传递,完全等同于下面两个 PUBLISH 命令:
PUBLISH __keyspace@0__:keyname set
PUBLISH __keyevent@0__:set keyname
一个频道允许监听所有以键 keyname 为目标的所有 event,以及另一个频道允许获取有关所有 SET 操作目标键的信息。
第一种事件在频道中使用keyspace前缀的被叫做键空间通知。
第二种事件使用 keyevent 前缀的,被叫做键事件通知
在以上例子中,为键 keyname 生成了一个set event。会发生什么:
键空间频道接收到的消息是事件的名称。键事件频道接收到的消息是键的名称。
可以只启用其中一种通知,以便只传递我们感兴趣的事件子集。
以下为常见的 Redis 命令对应的事件列表:
SET以及同类的SETEX、SETNX、GETSET:产生set事件,若使用SETEX则也会产生expire事件
MSET 将会为每个键都产生一个set事件
DEL 在某个键被删除时产生 del 事件
EXPIRE、PEXPIRE、EXPIREAT以及PEXPIREAT:当设置过期时间或未来时间的时间戳,则产生expire事件,否则产生del事件(将立即被删除)
LPUSH、LPUSHX与RPUSH、RPUSHX:根据插入的方向分别产生lpush或rpush事件
RPOP、LPOP 分别产生rpop与lpop事件,若移出的是列表中的最后一个元素,将会同时产生del事件
LSET 产生lset事件
LREM 产生lrem事件,同样若移除的元素为列表中的最后一个元素时将同时产生del事件
HSET、HSETNX以及HMSET 产生一个hset事件
HDEL 产生一个hdel事件,且在移除后哈希表为空的情况下产生del事件
SADD 产生一个sadd事件
SREM 产生一个srem事件,且在移除后集合为空的情况下产生del事件
SMOVE 原键中产生srem事件且在目标键中产生sadd事件
SINTERSTORE、SUNIONSTORE、SDIFFSTORE 分别产生sinterstore、sunionstore以及sdiffstore事件,且在结果为空集且目标键存在的情况下,将会产生del事件
ZADD 无论添加几个元素都只产生一个zadd事件
ZREM 无论移除几个元素都只产生一个zrem事件,当移除后有序集合为空时产生del事件
XADD 产生xadd事件,若使用MAXLEN子命令可能会同时产生xtrim事件
XDEL 产生xdel事件
PERSIST 如果对应的键所关联的过期事件成功被移除,则产生persist事件
在键发生过期时产生expired事件
在达到 maxmemory 设定的内存阈值后发生键淘汰时产生 evicted 事件
#### 会话一
redis> SUBSCRIBE __keyevent@0__:expired
1) "subscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
#### 会话二
# redis> SETEX greeting 1 "hello world"
# 等待1秒后:
1) "message"
2) "__keyevent@0__:expired"
3) "greeting"
#### 会话一
redis> PSUBSCRIBE __key*@*__:*
1) "psubscribe"
2) "__key*@*__:*"
3) (integer) 1
#### 会话二
redis> SET greeting "hello redis"
1) "pmessage"
2) "__key*@*__:*"
3) "__keyspace@0__:greeting"
4) "set"
1) "pmessage"
2) "__key*@*__:*"
3) "__keyevent@0__:set"
4) "greeting"
https://redis.io/docs/manual/keyspace-notifications/