比如,以下代码展示了客户端如何获取 0 号数据库中针对 message 键执行的所有命令。
redis> SUBSCRIBE __keyspace@0__:message Reading messages... (press Ctrl-C to quit) 1) "subscribe" // 订阅信息 2) "__keyspace@0__:message" 3) (integer) 1 1) "message" // 执行 SET 命令 2) "__keyspace@0__:message" 3) "set" 1) "message" // 执行 EXPIRE 命令 2) "__keyspace@0__:message" 3) "expire"
根据发回的通知显示,可见先后共有 SET 和 EXPIRE 两个命令对键 message 进行了操作。
像这一类关注“某个键执行了什么命令”的通知称为键空间通知(key-space notification),此外,还有另一类称为键事件通知(key-event notification),它们关注的是“某个命令被什么键执行了”。以下代码就是客户端如何获取 0 号数据库中所有执行了 DEL 命令的键的键事件通知的例子。
redis> SUBSCRIBE __keyevent@0__:del Reading messages... (press Ctrl-C to quit) 1) "subscribe" // 订阅信息 2) "__keyevent@0__:del" 3) (integer) 1 1) "message" // 键 key 执行了 DEL 命令 2) "__keyevent@0__:del" 3) "key" 1) "message" // 键 number 执行了 DEL 命令 2) "__keyevent@0__:del" 3) "number"
服务器的 notify-keyspace-events 配置选项值决定了服务器所发送通知的类型,如(更多设置可参考 Redis 的官方文档说明):
(1)值 AKE 表示想让服务器发送所有类型的键空间通知和键事件通知。
(2)值 AK 表示想让服务器发送所有类型的键空间通知。
(3)值 AE 表示想让服务器发送所有类型的键事件通知。
(4)值 KS 表示想让服务器只发送和字符串键有关的键空间通知。
(5)值 EL 表示想让服务器只发送和列表键有关的键事件通知。
发送数据库通知的功能是由 notifyKeyspaceEvent 函数实现的,其伪代码实现如下。
def notifyKeyspaceEvent(type, event, key, dbid): # 如果给定的通知不是服务器配置允许发送的通知,则直接返回 if not (server.notify_keyspace_events & type): return # 发送键空间通知 if server.notify_keyspace_events & REDIS_NOTIFY_KEYSPACE: # 将通知发送给频道“__keyspace@__: ” # 内容为键所发生的事件 # 构建频道名字 chan = "__keyspace@{dbid}__:{key}".format(dbid=dbid, key=key) # 发送通知 pubsubPublishMessage(chan, event) # 发送键事件通知 if server.notify_keyspace_events & REDIS_NOTIFY_KEYEVENT: # 将通知发送给频道“__keyevent@ __: ” # 内容为发生事件的键 # 构建频道名字 chan = "__keyevent@{dbid}__:{event}".format(dbid=dbid, event=event) # 发送通知 pubsubPublishMessage(chan, key)
其中的 pubsubPublishMessage 函数就是 PUBLISH 命令的实现函数,订阅数据库通知的客户端收到的信息就是由这个函数发出的,其具体实现细节留待后面再进行介绍。
参考书籍:《Redis 设计与实现》第 9 章——数据库。