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