《Redis的键空间通知详解》要点:
本文介绍了Redis的键空间通知详解,希望对您有用。如果有疑问,可以联系我们。
重要: 键空间通知(Keyspace Notification)是一个从Redis 2.8.0版本开始可用的功能.
一、功能概述
键空间通知使得客户端能够订阅Pub/Sub(发布/订阅)频道,这样客户端便能接收到以某种方式影响Redis数据集的事件.
可能接收到的事件示例,如下所示:
所有影响到一个给定键的命令.
所有接收到一个LPUSH命令的键.
所有数据库-0中的键全都过期.
Redis会使用标准的Pub/Sub层来传递事件,因此,实现了Pub/Sub功能的客户端能够直接使用这个功能,而不用进行任何修改.
因为Redis的Pub/Sub功能当前是“触发后不管(Fire and Forget)”的,所以如果你的应用程序对事件有着可靠通知的要求,那么它就不能使用Redis的键空间通知功能.也便是说,如果你的Pub/Sub客户端断开连接,然后再重新连接,那么在客户端断开连接的期间内传递的所有事件都会丢失.
Redis将来会改善事件传递的可靠性,但是很有可能会以一种更加常规的方式来办理这个问题,有可能会提高Pub/Sub功能自身的可靠性,也有可能会通过Lua脚本拦截Pub/Sub消息,然后再执行某些操作(例如,将事件存入一个列表之中).
二、事件类型
每次执行会影响到Redis数据空间的操作时,键空间通知就会发送两个不同类型的事件.以DEL操作为例,当删除数据库-0
中的一个名为mykey
的键时,将会触发Redis传递两条消息,完全等价于下面两条PUBLISH命令:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
很容易看出,如何让一个频道能够监听mykey
键相关的所有事件,以及如何让另一个频道能够获取del
操作所影响的所有的键的有关信息.
第一种类型的事件,频道名称的前缀为keyspace
,这种事件被称为键空间通知;而第二种类型的事件,频道名称的前缀为keyevent
,这种事件被称为键事件通知.
在上面的示例中,Redis会针对mykey
键产生一个del
事件.期间发生的事情,如下所示:
键空间频道会接收到一条消息,它的内容是事件名称.
键事件频道会接收到一条消息,它的内容是键的名称.
为了使Redis只传递我们感兴趣的事件子集,因此只可以使用一种类型的通知.
三、配置办法
在默认情况下,键空间的事件通知功能是禁用的,因为这个功能会消耗一些CPU性能,虽然几乎感觉不到性能消耗.有两种办法可以启用通知功能:修改redis.conf文件的notify-keyspace-events
参数,或者使用CONFIG SET命令.
将上述参数设置为空字符串,就能禁用通知功能.如果想要启用这个功能,那么就要将上述参数设置为一个空字符串,这个字符串由多个字符组成,其中的每个字符都具有特殊含义,如下表所示:
字符 | 含义 |
---|---|
K | 键空间(Keyspace)事件,通过__keyspace@<db>__ 前缀的频道发布. |
E | 键事件(Keyevent)事件,通过__keyevent@<db>__ 前缀的频道发布. |
g | 通用的命令(不特定类型),例如:DEL、EXPIRE、RENAME,等等. |
$ | 字符串(String)相关的命令. |
l | 列表(List)相关的命令. |
s | 集合(Set)相关的命令. |
h | 哈希(Hash)相关的命令. |
z | 有序集合相关的命令. |
x | 过期事件(每当一个键过期时,便会产生这种事件). |
e | 内存回收事件(当达到最大内存,然后回收某个键的内存时,便会产生这种事件). |
A | g$lshzxe的别名.因此,“AKE”字符串可以表示所有的事件. |
配置字符串至少应当包括K
或E
字符.否则,即使这个字符串包括其他任何字符,Redis也不会传递任何事件.
例如,若只想针对列表(List)启用键空间事件,则配置参数必需设置为Kl
,以此类推.
KEA
字符串可用于启用每种可能的事件.
四、不同命令产生的事件
不同的命令会产生不同类型的事件,如以下列表所示:
DEL
这个命令会为每个被删除的键产生一个del
事件.
RENAME
这个命令会产生两个事件,一个为原始键产生的rename_from
事件,以及一个为目标键产生的rename_to
事件.
EXPIRE
当为某个键设置过期时间时,这个命令便会产生一个expire
事件;或者,每当为某个待删除的键设置一个过期结果时,这个命令便会产生一个expired
事件(请参考EXPIRE命令的相关文档).
SORT
当使用STORE
选项来设置一个新键时,这个命令便会产生一个sortstore
事件.如果结果列表为空,并且使用了STORE
选项,并且已经存在一个同名的键,那么Redis便会删除这个已有的键,在这种情况下,这个命令还会产生一个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
事件.这两个事件的产生顺序都是固定不变的,先产生rpop
事件,然后再产生lpush
事件.另外,如果运行这两个命令之后,列表变为空表,那么便会删除这个列表对应的键,此时还会产生一个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
、sunionostore
和sdiffstore
事件.在特殊情况下,如果运行这些命令得到的集合为空,并且用于存储结果的键已经存在,那么这个键将会被删除,然后还会产生一个del
事件.
ZINCRBY
这个命令会产生一个zincr
事件.
ZADD
这个命令会产生一个zadd
事件,即使有多个输入元素时,也是如此.
ZREM
这个命令会产生一个zrem
事件,即使必要删除多个元素时,也是如此.如果运行这个命令之后,有序集合变为空,那么便会删除这个有序集合对应的键,此时还会产生一个del
事件.
ZREMRANGEBYSCORE
这个命令会产生一个zrembyscore
事件.如果运行这个命令之后,有序集合变为空,那么便会删除这个有序集合对应的键,此时还会产生一个del
事件.
ZREMRANGEBYRANK
这个命令会产生一个zrembyrank
事件.如果运行这个命令之后,有序集合变为空,那么便会删除这个有序集合对应的键,此时还会产生一个del
事件.
ZINTERSTORE、ZUNIONSTORE
这两个命令会分别产生zinterstore
和zunionstore
事件.在特殊情况下,如果运行这些命令得到的有序集合为空,并且用于存储结果的键已经存在,那么这个键将会被删除,然后还会产生一个del
事件.
每当一个键因为过期而被删除时,便会产生一个expired
事件.
每当一个键因为maxmemory
策略而被删除,以便于回收内存时,便会产生一个evicted
事件.
重要: 所有的命令只有当目标键真的被修改时,才会产生事件.例如,当使用SREM命令删除一个集合中并不存在的元素时,实际上没有改变这个键的对应值,所以也就不会产生任何事件.
如果还在怀疑一个给定命令的事件是如何产生的,那么最简单的办法便是自己验证一下.在Shell终端中运行以下命令:
redis-cli config set notify-keyspace-events KEA
redis-cli --csv psubscribe '__key*__:*'
此时,Redis客户端便进入频道监听状态,如下图所示:
此时,在另一个Shell终端中使用redis-cli
命令向Redis服务器发送命令:
redis-cli set foo hello
然后,便能在前一个Shell终端中观察到以下输出信息:
五、过期事件的产生时机
Redis会通过以下两种方式使得具有生存时间的键过期:
当使用某个命令拜访这个键,然后发现这个键已经过期.
通过一个后台系统在后台渐进地查找已经过期的键,这样还能够收集从未被拜访过的键.
当通过上述两种方式之一拜访某个键,并且发现这个键已经过期时,Redis就会产生expired
事件.结论便是,Redis服务器并不能保证每当键的生存时间降低至0的时候就能立刻产生expired
事件.
如果总是没有任何命令拜访这个已经过期的键,并且带有生存时间(TTL:Time To Live)的键非常多的话,那么就很有可能感觉到键的生存时间降低至0和产生expired
事件之间具有明显的延时.
基本上,只有当Redis服务器删除已经过期的键时才会产生expired
事件,而不是当键的生存时间在理论上降低至0的时候.
六、键空间通知示例
接下来,会通过实际操作,简单讲解Redis键空间通知的使用办法.
1. 安装Redis
依照《在CentOS上安装Redis缓存系统》安装Redis服务器.
2. 启用键空间通知功能
在Shell终端(此处取名为终端-1)中运行以下命令,进入Redis客户端的命令行:
redis-cli
然后在终端-1的Redis客户端的命令行中运行以下命令,启用键空间通知功能的所有通知:
config set notify-keyspace-events KEA
3. 订阅键空间通知和键事件通知
打开一个新的Shell终端(此处取名为终端-2),在其中运行以下命令,进入telnet命令行:
telnet localhost 6379
在终端-2的telnet命令行中,运行以下命令:
psubscribe __key*__:*
上述命令会订阅键空间通知和键事件通知,当对某个键执行修改命令时,终端-2便会同时收到上述两种通知.
4. 设置键的值
在终端-1的Redis客户端的命令行中运行以下命令,设置一个键的值:
set mykey hello
5. 观察结果
此时,便能在终端-2观察到两条通知消息,如下图所示:
上图的上半部分就是键空间通知,下半部分就是键事件通知.
《Redis的键空间通知详解》是否对您有启发,欢迎查看更多与《Redis的键空间通知详解》相关教程,学精学透。维易PHP学院为您提供精彩教程。