重要: Redis在2.8.0版本后支持键空间通知功能
键空间通知允许客户端订阅发布/订阅通道, 来接收某些影响Redis数据的事件回调.
例如发生下面这些事件:
因为是使用Redis常规的 发布/订阅层传递事件, 所以发布/订阅客户端不用修改就能使用这个功能.
因为Redis的发布/订阅目前是发送后不再关心(fire and forget), 所以如果你应用需要有可靠的通知事件, 那么就无法使用这个功能, 也就是说, 如果你的 发布/订阅 客户端断开了, 以及后面重连了, 所有在你断开时间内触发的事件都会丢失.
在未来, 有计划来允许更可靠的事件传递, 但是这可能将会在更一般的层面为 发布/订阅 本身带来可靠性, 或者允许Lua脚本截获 发布/订阅 的消息, 来执行像把事件推入列表志列的操作.
键空间通知是通过向影响Redis数据空间的每个操作发送两种不同类型的事件来实现的. 例如一个对在数据库0
中名为mykey
的键的 DEL操作, 将会触发两条消息传递, 这等效于下面两个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的notify-keyspace-events
来启用通知. 或者通过 CONFIG SET.
将参数设置为空字符串将会禁用通知. 为了启用该功能, 我们要使用由多个字符组成的非空字符串, 在下表中, 我们可以看到, 每个字符都有特殊的含义:
K 键空间事件, 通过 __keyspace@<db>__ 前缀发布.
E 键事件事件, 通过 __keyevent@<db>__ 前缀发布.
g 通用命令 (非特定类型) 例如 DEL, EXPIRE, RENAME, ...
$ 字符串命令
l 列表命令
s Set 命令
h Hash 命令
z 排序集命令
t 流命令
x 过期事件 (键过期时生成的事件)
e 撤出事件(当键由于最大内存策略而被撤出时生成的事件) Evicted events (events generated when a key is evicted for maxmemory)
A g$lshztxe的别名, so that the "AKE" string means all the events.
无论如何 K
或者 E
应该以字符串存在, 否则不管字符串其余部分是什么, 都不会传递任何事件.
例如, 仅启用列表的键空间事件, 配置参数必须设置为Kl
, 依此类推.
KEA
字符串可以被用来启用所有可能的事件.
下面列表展示了不同命令生成的事件.
del
事件.rename_from
是原始键的事件, 另一个rename_to
是目标键的事件.expire
事件, 当一个键设置为过期时, 或者生成每次对键设置正超时都会导致键被删除的expired
事件(更多详情查看 EXPIRE 文档).sortstore
事件, 当新的键设置成STORE
的时候生成. 如果结果列表为空, 且配置了STORE
属性, 并且存在了那个名称的键, 那么会把那个键删除, 因此这种情况下还会生成一个del
事件.set
事件. 然而SETEX 也会生成一个expire
事件.set
事件.setrange
事件.incrby
事件.incrbyfloat
事件.append
事件.lpush
事件, 即使在可变的情况下.rpush
事件, 即使在可变的情况下.rpop
事件. 另外因为列表最后一个元素被弹出, 所以键被移除, 会生成一个del
事件.lpop
事件. 另外因为列表最后一个元素被弹出, 所以键被移除, 会生成一个del
事件.linsert
事件.lset
事件.lrem
事件, 另外如果结果列表为空以及键被移除, 会生成一个del
事件.ltrim
事件, 另外如果结果列表为空以及键被移除, 会生成一个del
事件.rpop
事件和一个 lpush
事件. 在两种情况下都可以保证命令 (lpush
事件将经常在rpop
事件后传递). 另外如果结果列表为空以及键被移除会生成一个 del
事件.hset
事件.hincrby
事件.hincrbyfloat
事件.hdel
事件, 以及如果hash结果为空和键被移除的话, 会另外生成一个del
.sadd
事件,甚至在可变情况下.srem
事件, 如果结果set为空和键被移除, 会另外生成一个del
事件.srem
事件, 以及给目标键生成一个sadd
.spop
事件, 如果结果set为空和键被移除, 会另外生成素一个del
事件.sinterstore
, sunionstore
, sdiffstore
事件. 在特殊情况下, 结果set为空, 以及键已存在, 将会在键被移除时生成一个 del
事件.ZINCR
生成一个 zincr
事件.zadd
事件, 甚至当多节点被添加的时候.zrem
事件, 甚至当多节点被删除的时候. 当结果排序集为空和并生成键时, 一个额外的del
会被生成.ZREMBYSCORE
生成 zrembyscore
事件. 当排序结果集为空和生成键时,一个额外的del
会被生成.ZREMBYRANK
生成一个zrembyrank
事件. 当排序结果集为空和生成键时,一个额外的del
会被生成.zinterstore
和zunionstore
事件. 在特殊情况下, 结果set为空, 以及键已存在, 将会在键被移除时生成一个 del
事件.xadd
事件, 使用 MAXLEN
子命令时, 可能会伴随xtrim
事件.xdel
事件, 即使多个入口被删除.XGROUP CREATE
生成 xgroup-create
事件.XGROUP DELCONSUMER
生成xgroup-delconsumer
事件.XGROUP DESTROY
生成 xgroup-destroy
事件.XGROUP SETID
生成xgroup-setid
事件.XSETID
生成xsetid
事件.xtrim
事件.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服务器能够生成 expired
事件.
如果没有命令始终以这个键为目标, 并且有许多键与TTL关联, 那么在键的生存时间变为零的事件与expired
事件生成的时间之间会有很大的延迟.
基本上 expired
时间会在Redis服务器删除这个键的时候生成 , 而不是理论上的生存时间达到零值时.