Redis 键空间通知
实时监控 Redis 键和值的更改
键空间通知允许客户端订阅 Pub/Sub 通道,以便接收以某种方式影响 Redis 数据集的事件。
可以接收的事件示例包括
- 影响给定键的所有命令。
- 接收 LPUSH 操作的所有键。
- 数据库 0 中所有过期的键。
注意:Redis Pub/Sub 是 *发布即忘*,也就是说,如果您的 Pub/Sub 客户端断开连接,并在以后重新连接,则在客户端断开连接期间传递的所有事件都会丢失。
事件类型
键空间通知是通过为影响 Redis 数据空间的每个操作发送两种不同的事件类型来实现的。例如,针对数据库 `0` 中名为 `mykey` 的键的 `DEL` 操作将触发传递两条消息,完全等同于以下两个 `PUBLISH` 命令
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
第一个通道监听针对键 `mykey` 的所有事件,而另一个通道只监听键 `mykey` 上的 `del` 操作事件
第一种事件,在通道中带有 `keyspace` 前缀,称为 **键空间通知**,而第二种,带有 `keyevent` 前缀,称为 **键事件通知**。
在前面的示例中,为键 `mykey` 生成了一个 `del` 事件,导致两条消息
- 键空间通道接收事件名称作为消息。
- 键事件通道接收键名称作为消息。
可以仅启用一种类型的通知,以便仅传递我们感兴趣的事件子集。
配置
默认情况下,键空间事件通知被禁用,因为虽然不太明智,但该功能会使用一些 CPU 资源。可以使用 redis.conf 中的 notify-keyspace-events
或通过 CONFIG SET 来启用通知。
将参数设置为空字符串将禁用通知。为了启用该功能,可以使用一个非空字符串,该字符串由多个字符组成,每个字符根据下表具有特殊含义
K Keyspace events, published with __keyspace@<db>__ prefix.
E Keyevent events, published with __keyevent@<db>__ prefix.
g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
$ String commands
l List commands
s Set commands
h Hash commands
z Sorted set commands
t Stream commands
d Module key type events
x Expired events (events generated every time a key expires)
e Evicted events (events generated when a key is evicted for maxmemory)
m Key miss events (events generated when a key that doesn't exist is accessed)
n New key events (Note: not included in the 'A' class)
A Alias for "g$lshztxed", so that the "AKE" string means all the events except "m" and "n".
字符串中至少应包含 K
或 E
,否则无论字符串的其余部分如何,都不会传递任何事件。
例如,要仅为列表启用键空间事件,则必须将配置参数设置为 Kl
,依此类推。
可以使用字符串 KEA
来启用大多数类型的事件。
不同命令生成的事件
根据以下列表,不同的命令会生成不同类型的事件。
APPEND
生成append
事件。COPY
生成copy_to
事件。DEL
为每个删除的键生成del
事件。EXPIRE
及其所有变体 (PEXPIRE
,EXPIREAT
,PEXPIREAT
) 在使用正超时值(或未来时间戳)调用时会生成expire
事件。请注意,当使用负超时值或过去的时间戳调用这些命令时,键将被删除,并且只会生成del
事件。HDEL
生成一个hdel
事件,如果结果哈希为空并且键被删除,则会生成一个额外的del
事件。HEXPIRE
及其所有变体 (HEXPIREAT
,HPEXPIRE
,HPEXPIREAT
) 生成hexpire
事件。此外,当字段过期时会生成hexpired
事件。HINCRBYFLOAT
生成hincrbyfloat
事件。HINCRBY
生成hincrby
事件。HPERSIST
生成hpersist
事件。HSET
,HSETNX
和HMSET
都生成一个hset
事件。INCRBYFLOAT
生成incrbyfloat
事件。INCR
,DECR
,INCRBY
,DECRBY
命令都生成incrby
事件。LINSERT
生成linsert
事件。LMOVE
和BLMOVE
生成lpop
/rpop
事件(取决于 wherefrom 参数)和lpush
/rpush
事件(取决于 whereto 参数)。在这两种情况下,顺序都有保证(lpush
/rpush
事件将始终在lpop
/rpop
事件之后传递)。此外,如果结果列表的长度为零并且键被删除,则会生成del
事件。LPOP
生成lpop
事件。此外,如果由于从列表中弹出了最后一个元素而删除了键,则会生成del
事件。LPUSH
和LPUSHX
生成一个lpush
事件,即使在可变参数情况下也是如此。LREM
生成lrem
事件,如果结果列表为空并且键被删除,则会生成额外的del
事件。LSET
生成lset
事件。LTRIM
生成ltrim
事件,如果结果列表为空并且键被删除,则会生成额外的del
事件。MIGRATE
如果源键被删除,则会生成del
事件。MOVE
生成两个事件,一个move_from
事件用于源键,一个move_to
事件用于目标键。MSET
为每个键生成一个单独的set
事件。PERSIST
如果与键关联的过期时间已成功删除,则会生成persist
事件。RENAME
生成两个事件,一个rename_from
事件用于源键,一个rename_to
事件用于目标键。RESTORE
为键生成restore
事件。RPOPLPUSH
和BRPOPLPUSH
生成rpop
事件和lpush
事件。在这两种情况下,顺序都有保证(lpush
事件将始终在rpop
事件之后传递)。此外,如果结果列表的长度为零并且键被删除,则会生成del
事件。RPOP
生成rpop
事件。此外,如果由于从列表中弹出了最后一个元素而删除了键,则会生成del
事件。RPUSH
和RPUSHX
生成一个rpush
事件,即使在可变参数情况下也是如此。SADD
生成一个sadd
事件,即使在可变参数情况下也是如此。SETRANGE
生成setrange
事件。SET
及其所有变体 (SETEX
,SETNX
,GETSET
) 生成set
事件。但是,SETEX
还会生成expire
事件。SINTERSTORE
,SUNIONSTORE
,SDIFFSTORE
分别生成sinterstore
,sunionstore
,sdiffstore
事件。在特殊情况下,结果集为空,并且存储结果的键已存在,则会生成del
事件,因为键被删除。SMOVE
为源键生成srem
事件,为目标键生成sadd
事件。SORT
在使用STORE
设置新键时生成sortstore
事件。如果结果列表为空,并且使用了STORE
选项,并且之前已经存在具有该名称的键,则结果是键被删除,因此在这种情况下会生成del
事件。SPOP
生成spop
事件,如果结果集为空并且键被删除,则会生成额外的del
事件。SREM
生成一个srem
事件,如果结果集为空并且键被删除,则会生成额外的del
事件。XADD
生成xadd
事件,可能在与MAXLEN
子命令一起使用时紧随其后的是xtrim
事件。XDEL
即使删除多个条目,也会生成一个xdel
事件。XGROUP CREATECONSUMER
生成xgroup-createconsumer
事件。XGROUP CREATE
生成xgroup-create
事件。XGROUP DELCONSUMER
生成xgroup-delconsumer
事件。XGROUP DESTROY
生成xgroup-destroy
事件。XGROUP SETID
生成xgroup-setid
事件。XSETID
生成xsetid
事件。XTRIM
生成xtrim
事件。ZADD
即使添加多个元素,也会生成一个zadd
事件。ZDIFFSTORE
,ZINTERSTORE
和ZUNIONSTORE
分别生成zdiffstore
,zinterstore
和zunionstore
事件。在特殊情况下,结果排序集为空,并且存储结果的键已存在,则会生成del
事件,因为键被删除。ZINCRBY
生成zincr
事件。ZREMRANGEBYRANK
生成一个zrembyrank
事件。当结果排序集为空并且键被生成时,会生成额外的del
事件。ZREMRANGEBYSCORE
生成一个zrembyscore
事件。当结果排序集为空并且键被生成时,会生成额外的del
事件。ZREM
即使删除多个元素,也会生成一个zrem
事件。当结果排序集为空并且键被生成时,会生成额外的del
事件。- 每次由于过期而从数据集删除与生存时间关联的键时,都会生成
expired
事件。 - 每次由于
maxmemory
策略而从数据集删除键以释放内存时,都会生成evicted
事件。 - 每次将新键添加到数据集时,都会生成
new
事件。
重要 所有命令只有在目标键确实被修改时才会生成事件。例如,SREM
从集合中删除一个不存在的元素实际上不会改变键的值,因此不会生成任何事件。
如果你不确定某个命令如何生成事件,最简单的方法是自己观察
$ redis-cli config set notify-keyspace-events KEA
$ redis-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1
此时,在另一个终端中使用 redis-cli
向 Redis 服务器发送命令,并观察生成的事件
"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...
过期事件的时序
Redis 通过两种方式使与生存时间关联的键过期
- 当键被命令访问并且发现已过期时。
- 通过后台系统,该系统在后台以增量方式查找过期的键,以便能够收集从不访问的键。
当键被访问并且发现已过期时,上述系统之一会生成 expired
事件,因此无法保证 Redis 服务器能够在键的生存时间达到零值时生成 expired
事件。
如果没有命令不断地针对键,并且存在许多与 TTL 关联的键,那么键的生存时间降至零值与生成 expired
事件之间可能会有明显的延迟。
当 Redis 服务器删除键时,会生成过期 (expired
) 事件,而不是在生存时间理论上达到零值时生成。
集群中的事件
每个 Redis 集群节点都会生成关于其自身键空间子集的事件,如上所述。但是,与集群中常规的发布/订阅通信不同,事件通知**不会**广播到所有节点。换句话说,键空间事件是特定于节点的。这意味着,为了接收集群的所有键空间事件,客户端需要订阅每个节点。
@history
>= 6.0
:添加了键丢失事件。>= 7.0
:添加了事件类型new