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