重要 键空间通知是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@<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
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".
至少K
或E
必须在字符串中出现,否则剩余的字符串中将不会有事件会被传递。
例如,为列表仅开启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
,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
事件,如果键关联的过期时间被成功删除的话。 - 每当一个关联了生存时间的键因为过期而被从数据集中删除时,一个
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
:增加了键丢失事件