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".

字符串中至少应包含 KE,否则无论字符串的其余部分如何,都不会传递任何事件。

例如,要仅为列表启用键空间事件,则必须将配置参数设置为 Kl,依此类推。

可以使用字符串 KEA 来启用大多数类型的事件。

不同命令生成的事件

根据以下列表,不同的命令会生成不同类型的事件。

  • APPEND 生成 append 事件。
  • COPY 生成 copy_to 事件。
  • DEL 为每个删除的键生成 del 事件。
  • EXPIRE 及其所有变体 (PEXPIREEXPIREATPEXPIREAT) 在使用正超时值(或未来时间戳)调用时会生成 expire 事件。请注意,当使用负超时值或过去的时间戳调用这些命令时,键将被删除,并且只会生成 del 事件。
  • HDEL 生成一个 hdel 事件,如果结果哈希为空并且键被删除,则会生成一个额外的 del 事件。
  • HEXPIRE 及其所有变体 (HEXPIREATHPEXPIREHPEXPIREAT) 生成 hexpire 事件。此外,当字段过期时会生成 hexpired 事件。
  • HINCRBYFLOAT 生成 hincrbyfloat 事件。
  • HINCRBY 生成 hincrby 事件。
  • HPERSIST 生成 hpersist 事件。
  • HSETHSETNXHMSET 都生成一个 hset 事件。
  • INCRBYFLOAT 生成 incrbyfloat 事件。
  • INCRDECRINCRBYDECRBY 命令都生成 incrby 事件。
  • LINSERT 生成 linsert 事件。
  • LMOVEBLMOVE 生成 lpop/rpop 事件(取决于 wherefrom 参数)和 lpush/rpush 事件(取决于 whereto 参数)。在这两种情况下,顺序都有保证(lpush/rpush 事件将始终在 lpop/rpop 事件之后传递)。此外,如果结果列表的长度为零并且键被删除,则会生成 del 事件。
  • LPOP 生成 lpop 事件。此外,如果由于从列表中弹出了最后一个元素而删除了键,则会生成 del 事件。
  • LPUSHLPUSHX 生成一个 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 事件。
  • RPOPLPUSHBRPOPLPUSH 生成 rpop 事件和 lpush 事件。在这两种情况下,顺序都有保证(lpush 事件将始终在 rpop 事件之后传递)。此外,如果结果列表的长度为零并且键被删除,则会生成 del 事件。
  • RPOP 生成 rpop 事件。此外,如果由于从列表中弹出了最后一个元素而删除了键,则会生成 del 事件。
  • RPUSHRPUSHX 生成一个 rpush 事件,即使在可变参数情况下也是如此。
  • SADD 生成一个 sadd 事件,即使在可变参数情况下也是如此。
  • SETRANGE 生成 setrange 事件。
  • SET 及其所有变体 (SETEXSETNXGETSET) 生成 set 事件。但是,SETEX 还会生成 expire 事件。
  • SINTERSTORESUNIONSTORESDIFFSTORE 分别生成 sinterstoresunionstoresdiffstore 事件。在特殊情况下,结果集为空,并且存储结果的键已存在,则会生成 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 事件。
  • ZDIFFSTOREZINTERSTOREZUNIONSTORE 分别生成 zdiffstorezinterstorezunionstore 事件。在特殊情况下,结果排序集为空,并且存储结果的键已存在,则会生成 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
RATE THIS PAGE
Back to top ↑