
重要: 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服务器删除这个键的时候生成 , 而不是理论上的生存时间达到零值时.