实时监控 Redict 键和值的更改
键空间通知允许客户端订阅 Pub/Sub 频道,以接收以某种方式影响 Redict 数据集的事件。
可以接收的事件示例包括:
- 影响给定键的所有命令。
- 接收 LPUSH 操作的所有键。
- 在数据库 0 中过期的所有键。
注意:Redict Pub/Sub 是 fire and forget 的,也就是说,如果您的 Pub/Sub 客户端断开连接,并且在稍后重新连接,客户端断开连接期间传递的所有事件都会丢失。
事件类型
键空间通知通过为每个影响 Redict 数据空间的操作发送两种不同类型的事件来实现。例如,针对数据库 0 中名为 mykey 的键的 DEL 操作将触发传递两个消息,这两个消息与以下两个 PUBLISH 命令完全等效:
PUBLISH __keyspace@0__:mykey delPUBLISH __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
