Redis 键空间通知

实时监控Redis键和值的变化

Keyspace 通知允许客户端订阅 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事件,导致了两条消息:

  • Key-space 通道接收事件名称作为消息。
  • 键事件通道接收的消息是键的名称。

可以仅启用一种通知类型,以便仅传递我们感兴趣的事件子集。

配置

默认情况下,键空间事件通知是禁用的,因为尽管不是非常敏感,该功能会消耗一些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 及其所有变体(PEXPIRE, EXPIREAT, PEXPIREAT)在调用时如果设置了正数的超时时间(或将来的时间戳),则会生成一个 expire 事件。请注意,当这些命令使用负数的超时值或过去的时间戳调用时,键将被删除,并且只会生成一个 del 事件。
  • HDEL 生成一个单一的 hdel 事件,如果生成的哈希为空并且键被移除,则还会生成一个额外的 del 事件。
  • HEXPIRE 及其所有变体(HEXPIREAT, HPEXPIRE, HPEXPIREAT)生成 hexpire 事件。此外,当字段过期时,会生成 hexpired 事件。
  • HINCRBYFLOAT 生成一个 hincrbyfloat 事件。
  • HINCRBY 生成一个 hincrby 事件。
  • HPERSIST 生成一个 hpersist 事件。
  • HSET, HSETNXHMSET 都会生成一个单一的 hset 事件。
  • INCRBYFLOAT 生成一个 incrbyfloat 事件。
  • INCR, DECR, INCRBY, DECRBY 命令都会生成 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 及其所有变体(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, ZINTERSTOREZUNIONSTORE 分别生成 zdiffstore, zinterstorezunionstore 事件。在特殊情况下,如果生成的排序集合为空,并且存储结果的键已经存在,则会生成一个 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事件之间可能会有显著的延迟。

过期(expired)事件是在Redis服务器删除键时生成的,而不是在理论上生存时间达到零值时生成的。

集群中的事件

Redis集群的每个节点都会生成关于其自身键空间子集的事件,如上所述。然而,与集群中的常规发布/订阅通信不同,事件通知不会广播到所有节点。换句话说,键空间事件是节点特定的。这意味着要接收集群的所有键空间事件,客户端需要订阅每个节点。

@历史

  • >= 6.0: 添加了键缺失事件。
  • >= 7.0: 事件类型 new 已添加
RATE THIS PAGE
Back to top ↑