Redis键空间通知

重要 键空间通知是2.8.0以后版本可用的一个特性。

特性概览

键空间通知允许客户端订阅Pub/Sub通道,以便接收对Redis数据集的某些方面影响的事件。

可以被接收的事件的例子:

  • 影响给定键的所有命令。
  • 接收一个LPUSH操作的所有键。
  • 在数据库0所有过期的键。

事件使用Redis的Pub/Sub层来传递,所以客户端可以使用这些特征实现Pub/Sub而不需要做修改。

因为Redis Pub/Sub是发射既忘(fire and forget),目前没有办法使用这个特征,如果你的应用需求是事件的可信通知的话,那是因为,如果你的Pub/Sub客户端失去连接,且稍后重连接时,所有的事件在重新连接时都丢失。

未来有计划允许更可靠的事件传递,不过这将很可能定位在更一般层级上的,要么是给Pub/Sub本身带来可靠性,要么是允许Lua脚本拦截Pub/Sub消息以执行诸如将事件推入列表这样的操作。

事件类型

键空间的通知通过为每个影响Redis数据空间的操作发送两种不同的事件类型实现。比如,一个DEL操作命中数据库0中名为mykey的键将触发传递2个消息,准确来说等于下面的两个PUBLISH命令:

PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey

很容易的看到,一个通道是如何允许我们监听命中键mykey的所有事件,并且其他通道允许获取关于del操作的目标的所有键的信息。

第一种类型是通道中的以keyspace为前缀,被称为Key-space notification的事件,而第二种,是以keyevent为前缀,被称为Key-event notification的事件。

在上面的例子中,一个del事件为键mykey而生成。会发生什么:

  • 键空间通道接收了以事件为名称的消息。
  • 键事件通道接收了以键为名称的消息。

为了传递我们感兴趣的子集的事件,仅开启通知中的一种是可能的。

配置

默认键空间事件通知是关闭的,因为这个功能使用了一些不能明确感知的CPU电源。是用redis.conf中的notify-keyspace-events或者通过CONFIG SET开启通知。

设置参数到空字符串禁止通知。为了开启一个已经使用的非空字符串的特征,组合多个字符,每个字符有一个特殊的意味,就像下面的表格一样:

K     Keyspace events, published with __keyspace@__ prefix.
E     Keyevent events, published with __keyevent@__ 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
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)
A     Alias for "g$lshztxe", so that the "AKE" string means all the events except "m".

至少KE必须在字符串中出现,否则剩余的字符串中将不会有事件会被传递。

例如,为列表仅开启Key-space事件,这个配置参数必须设置为K1,等等。

字符串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事件。
  • 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)。
  • LMOVE 和 BLMOVE 生成一个lpop/rpop事件(取决于来向参数)和一个lpush/rpush事件(取决于去向参数)。在这两种情况下顺序都是有保障的(lpush/rpush事件总是在lpop/rpop事件之后传递)。当结果列表长度为0并且该键被移除后,会产生一个额外的del事件。
  • HSET, HSETNX 和 HMSET 都生成一个hset事件。
  • HINCRBY生成一个hincrby事件。
  • HINCRBYFLOAT 生成一个hincrbyfloat 事件。
  • HDEL 生成一个单独的hdel事件,如果结果哈希为空且被移除的话,会生成一个额外的del事件。
  • SADD 生成一个单独的sadd事件,甚至在可变参的情形中。
  • SREM 生成一个srem事件,如果结果集为空且键被移除的话,会生成一个额外的del事件。
  • 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, zinterstorezunionstore 事件。在特殊情况下,当结果有序集合为空,且键已经在存储结果中存在时,如果键被移除会生成一个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 事件,如果键关联的过期时间被成功删除的话。
  • 每当一个关联了生存时间的键因为过期而被从数据集中删除时,一个expired事件生成了。
  • 每当出于maxmemory策略的结果,将一个键从数据集中回收从而释放内存的时候,一个evicted事件就会生成。

重要 所有的命令只在目标键真实改变时生成事件。比如,一个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服务器能够在键的生存时间到0时生成expired事件。

如果没有命令经常访问键,且有很多有TTL关联的键,在键的生存时间降低为0和生成expired事件的时间之间将会有一个较大的延迟。

基本上来讲,是当Redis服务器删除键时而并不是键的理论的生存时间到达为0时,生成expired事件。

集群中的事件

如上所述,每个Redis集群生成自己键空间的子集。可是,不像规则的Pub/Sub在集群中的通讯,事件通知不是广播到所有的节点。不同的是,键空间事件是节点特异性的。这意味着,为了接收集群的所有的键空间事件,客户端需要订阅每个节点。

History 记录

  • >= 6.0:增加了键丢失事件

你可能感兴趣的:(Redis键空间通知)