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
事件生成的那一刻之间可能会有显著的延迟。
过期 (expired
) 事件在 Redis 服务器删除该键时生成,而不是在过期时间理论上达到零值时。
集群中的事件
如上所述,Redis 集群的每个节点都生成关于其自身键空间子集的事件。然而,与集群中常规的 Pub/Sub 通信不同,事件通知不会广播到所有节点。换句话说,键空间事件是特定于节点的。这意味着,要接收集群的所有键空间事件,客户端需要订阅每个节点。
@history
>= 6.0
: 添加了 Key miss 事件。>= 7.0
: 添加了事件类型new