Redis的键空间通知(keyspace notifications)功能是自2.8.0版本开始加入的,客户端可以通过订阅/发布(Pub/Sub)机制,接收那些以某种方式改变了Redis数据空间的事件通知。比如:所有改变给定key的命令;所有经过lpush操作的key;所有在0号数据库中过期的key等等。

通知是通过Redis的订阅/发布机制发送的,因此,所有支持订阅/发布功能的客户端都可在无需调整的情况下,使用键空间通知功能。

Redis的发布/订阅目前是即发即弃(fire and forget)模式的,因此无法实现事件的可靠通知。也就是说,如果发布/订阅的客户端断链之后又重连,则在客户端断链期间的所有事件都丢失了。

未来计划支持事件的可靠通知,但是这可能会通过让订阅与发布功能本身变得更可靠来实现,也可能会在Lua脚本中对消息的订阅与发布进行监听,从而实现类似将事件推入到列表这样的操作。

一:事件的类型

针对改变Redis数据空间的每个操作,键空间通知都会发送两类不同的事件。

比如在0号数库中,执行del mykey操作,将会触发两个消息,等价于执行下面两个publish命令:

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

一个频道发布0号数据库中,所有针对mykey键执行的操作,这类事件,以keyspace为前缀,称为keyspace通知;

另一个频道发布0号数据库中,所有成功执行del操作的键,这类事件,以keyevent为前缀,称为keyevent通知;

在上面的例子中,当执行del  mykey时,会发生:

a:keyspace频道的订阅者会收到消息,消息中包含键执行的操作的名字;

b:keyevent频道的订阅者会收到消息,消息中包含执行某种操作的键的名字;

可以通过配置,使Redis仅发送某一类我们感兴趣的通知。

二:配置

因键空间通知功能需要耗费一定的CPU时间,因此默认情况下,该功能是关闭的。可以通过修改配置文件redis.conf,或者通过CONFIG SET命令,设置notify-keyspace-events选项,来启用或关闭该功能。

该选项的值为空字符串时,该功能禁用,选项值为非空字符串时,启用该功能,非空字符串由特定的多个字符组成,每个字符表示不同的意义:

K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;

E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;

g:一般性的,非特定类型的命令,比如del,expire,rename等;

$:字符串特定命令;

l:列表特定命令;

s:集合特定命令;

h:哈希特定命令;

z:有序集合特定命令;

x:过期事件,当某个键过期并删除时会产生该事件;

e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;

A:g$lshzxe的别名,因此”AKE”意味着所有事件。

注意,该选项的值中至少需要包含K或者E,否则不会发布任何事件。比如,如果需要开启针对列表的keyspace事件通知,则该选项需要配置为“Kl”;

三:不同命令产生的事件通知

DEL 命令为每个被删除的键产生一个 del 事件;

RENAME 产生两个事件:为源键产生一个 rename_from 事件,并为目标键产生一个 rename_to 事件;

EXPIRE命令,在设置键的过期时间时产生一个 expire事件;当键因过期而被删除时,产生一个 expired事件;

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 事件。两个命令都保证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 事件;

ZINCR产生一个 zincr 事件;

ZADD 产生一个 zadd事件,即使有多个输入元素时,也是如此;

ZREM 产生一个 zrem 通知,即使有多个输入元素时,也是如此。如果执行 ZREM 之后,有序集合键被清空,则还会产生一个 del 事件;

ZREMEBYSCORE 产生一个 zrembyscore事件,如果用于保存结果的键已经存在,则还会产生一个 del 事件。

ZREMBYRANK 产生一个 zrembyrank事件,如果用于保存结果的键已经存在,则还会产生一个 del 事件。

ZINTERSTORE 和 ZUNIONSTORE 分别产生 zinterstore 和 zunionstore 两种事件。如果用于保存结果的键已经存在,那么还会产生一个 del 事件。

每当一个键因为过期而被删除时,产生一个 expired 事件。

每当一个键因为 maxmemory策略而被删除并回收内存时,产生一个 evicted 事件。

注意:所有命令都只在键真的被改动了之后,才会产生事件通知。比如,当srem命令试图删除不存在于集合的元素时,删除操作执行失败,因为没有真正的改动键,所以这一操作不会发送通知。

四:expired事件通知的发送时间

Redis 使用以下两种方式删除过期的键:

a:当一个键被访问时,程序会对这个键进行检查,如果键已过期,则删除该键;

b:系统会在后台定期扫描并删除那些过期的键;

当过期键被以上两种方式中的任意一种发现并且删除时,才会产生expired事件通知。

Redis不保证生存时间(TTL)变为 0 的键会立即被删除:如果没有命令访问这个键,或者设置生存时间的键非常多的话,那么在键的生存时间变为0,到该键真正被删除,这中间可能会有一段比较显著的时间间隔。

因此,Redis产生expired事件通知的时间,是过期键被删除的时候,而不是键的生存时间变为 0 的时候。

五:实践

1:Redis发布所有通知,客户端A订阅所有消息:

127.0.0.1:6379> config set notify-keyspace-events KEA
OK
127.0.0.1:6379> psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__key*@0__:*"
3) (integer) 1

然后,在客户端B上执行set和del命令:

127.0.0.1:6379> set msg "hello"
OK
127.0.0.1:6379> del msg
(integer) 1
127.0.0.1:6379> del msg
(integer) 0

然后客户端A的打印如下:

1) "pmessage"
2) "__key*@0__:*"
3) "__keyspace@0__:msg"
4) "set"
1) "pmessage"
2) "__key*@0__:*"
3) "__keyevent@0__:set"
4) "msg" 1) "pmessage"
2) "__key*@0__:*"
3) "__keyspace@0__:msg"
4) "del"
1) "pmessage"
2) "__key*@0__:*"
3) "__keyevent@0__:del"
4) "msg"

可见,针对每一个操作,客户端A都收到了两种消息,分别是keyspace和keyevent消息。

 

2:使Redis仅发布keyspace通知,而客户端A订阅所有消息类型:

127.0.0.1:6379> config set notify-keyspace-events KA
OK
127.0.0.1:6379> psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__key*@0__:*"
3) (integer) 1

在客户端B上执行,与上面同样的步骤。此时,客户端A上的打印:

1) "pmessage"
2) "__key*@0__:*"
3) "__keyspace@0__:msg"
4) "set" 1) "pmessage"
2) "__key*@0__:*"
3) "__keyspace@0__:msg"
4) "del"

可见,尽管客户端A订阅了所有消息,但是Redis仅发布了keyspace事件。而且,在客户端B上执行了两次del操作,而只有第一个del成功执行了,从而产生了一个事件。

3:Redis发布所有通知,客户端A仅订阅keyspace消息:

127.0.0.1:6379> config set notify-keyspace-events KEA
OK
127.0.0.1:6379> psubscribe __keyspace@0__:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyspace@0__:*"
3) (integer) 1

在客户端B上,执行与上面同样的步骤。然后客户端A的打印如下:

1) "pmessage"
2) "__keyspace@0__:*"
3) "__keyspace@0__:msg"
4) "set" 1) "pmessage"
2) "__keyspace@0__:*"
3) "__keyspace@0__:msg"
4) "del"

可见,针对每一个操作,客户端A只收到了keyspace消息。

4:Redis仅发布字符串特定类型的通知,客户端A订阅所有类型的消息:

127.0.0.1:6379> config set notify-keyspace-events KE$
OK
127.0.0.1:6379> psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__key*@0__:*"
3) (integer) 1

在客户端B上,分别执行lpush,set和del命令:

127.0.0.1:6379> lpush alist 1 2 3
(integer) 3
127.0.0.1:6379> set msg "hello"
OK
127.0.0.1:6379> del msg
(integer) 1

此时,客户端A上的打印:

1) "pmessage"
2) "__key*@0__:*"
3) "__keyspace@0__:msg"
4) "set" 1) "pmessage"
2) "__key*@0__:*"
3) "__keyevent@0__:set"
4) "msg"

可见,针对字符串,产生了keyspace和keyevent类型的消息,而针对列表的lpush命令并没有产生消息,而且,del命令是非特定类型的命令,也没有产生消息。

参考:

http://www.phperz.com/article/15/0904/153987.html

http://redis.io/topics/notifications

10Redis键空间通知(keyspace notifications)的更多相关文章

  1. redis键空间通知(keyspace notification)

    一.需求 在redis中,设置好key和生存时间之后,希望key过期被删除时能够及时的发送一个通知告诉我key,以便我做后续的一些操作. 二.环境 系统:windows10 php:7.1 redis ...

  2. 利用Redis keyspace notification(键空间通知)实现过期提醒

    一.序言: 本文所说的定时任务或者说计划任务并不是很多人想象中的那样,比如说每天凌晨三点自动运行起来跑一个脚本.这种都已经烂大街了,随便一个 Crontab 就能搞定了. 这里所说的定时任务可以说是计 ...

  3. Redis键空间通知(keyspace notification),事件订阅

      Redis键空间通知(keyspace notification),事件订阅   应用场景:有效期优惠券.24小时内支付.下单有效事件等等. 功能概览 键空间通知使得客户端可以通过订阅频道或模式, ...

  4. KeySpaceNotification 键空间通知

    KeySpaceNotification 键空间通知 1.Redis键淘汰机制简介 在Redis中,内存的大小是有限的,所以为了防止内存饱和,需要实现某种键淘汰策略.主要有两种方法,一种是当Redis ...

  5. Redis源码解析:09redis数据库实现(键值对操作、键超时功能、键空间通知)

    本章对Redis服务器的数据库实现进行介绍,说明Redis数据库相关操作的实现,包括数据库中键值对的添加.删除.查看.更新等操作的实现:客户端切换数据库的实现:键超时相关功能的实现.键空间事件通知等. ...

  6. redis过期回调以及键空间通知

    背景 最近需要涉及一个定时通知的业务,之前的办法是采用定时任务,每秒查询一次.后来了解到Redis的键空间通知机制,其中的过期通知,和业务非常贴合. 键空间通知 下面是Redis中文文档的介绍 键空间 ...

  7. python中的Redis键空间通知(过期回调)

    介绍 Redis是一个内存数据结构存储库,用于缓存,高速数据摄取,处理消息队列,分布式锁定等等. 使用Redis优于其他内存存储的优点是Redis提供持久性和数据结构,如列表,集合,有序集和散列. 在 ...

  8. Redis 键空间通知

    [Redis 键空间通知] 键空间通知使得客户端可以通过订阅频道或模式, 来接收那些以某种方式改动了 Redis 数据集的事件. 以下是一些键空间通知发送的事件的例子: 所有修改键的命令. 所有接收到 ...

  9. Cassandra 键空间(keyspace),表(table)

    查看用户下信息: describe cluster; desc cluster;   查看所有keyspace: describe keyspaces; desc keyspaces;   查看key ...

随机推荐

  1. agc014F Strange Sorting

    这套题比较简单,以为自己能够独立A掉D和E,或许就能自己A掉F,看来还真是想多了 题意:给一个$n$的全排列,每次操作把$max(a[1],a[2],...,a[i]) = a[i]$的记为$high ...

  2. 前端插件--isCroll的使用

    中文文档地址: http://wiki.jikexueyuan.com/project/iscroll-5/ 效果图: <!DOCTYPE html> <html lang=&quo ...

  3. 中断描述符表 IDT

    保护模式下三个重要的系统表——GDT.LDT和IDT 这里主要是解释中断描述符表 中断描述符表IDT将每个异常或中断向量分别与它们的处理过程联系起来.与GDT和LDT表类似,IDT也是由8字节长描述符 ...

  4. 微信小程序之threejs全景

    最近在开发小程序,身心疲惫,原因是功能和app相同,我裂开了. 各种封装组件,各种写页面,不过有个好处是以前写的h5拿来改一下标签,基本上还是ok的,就剩下最后几个功能,其中就有一个VR全景功能. 移 ...

  5. django中的聚合索引

    Django(元信息)元类建索引 ORM查询(sql优化)优化 自定义聚合函数 Django的元类建索引————索引:索引的一个主要目的就是加快检索表中数据,索引是经过某种算法优化过的,因而查找次数要 ...

  6. mvp例子与MVVM例子

    VMP例子 <!-- 从百度CDN上面找个jquery的链接 --> <!DOCTYPE html> <html lang="en"> < ...

  7. 为什么我要使用Linux,使用Linux的十个理由。

    Linux一来都是做为服务器运行,这些年来,Linux的图形界面已经有了很大的改善,Linux已经成为一个完善的,用户友好的桌面操作系统了,有非多常多的人在使用Linux,下面是我们认为最必要的10个 ...

  8. 通过工具SQLyog进行导入数据

    可以通过工具SQLyog进行图形化导入数据. 1.准备好Excel表格 2.将excel表格数据导入到mysql数据库 (1)打开准备好的excel表,选择格式 另存为csv. (2)如果准备的exc ...

  9. 从0开始学习 GitHub 系列之「05.Git 进阶」

    关于 Git 相信大家看了之前一系列的文章已经初步会使用了, 但是关于Git还有很多知识与技巧是你不知道的,今天就来给大家介绍下一些 Git 进阶的知识. 1. 用户名和邮箱 我们知道我们进行的每一次 ...

  10. SQL中null比较的雷区

    SQL中遇到null要格外小心! oracle最坑: oracle中在可为null的字段上做逻辑关系运算要格外小心,如 <>,>,=,<,任何与null的运算结果都返回fals ...