之前几节已经学习过fanout exchange,direct exchange的使用,并用他们构建了一个日志系统,尽管direct exchange使得我们的日志系统更实用化,但是仍然有局限性,因为我们只是根据了日志的严重等级(info,warning,error)进行了分发,但是没关心日志的来源(auth / cron / kern ...)。但是Topic exchange更加灵活,能满足我们的需求,如:我们想监听来自cron的重要错误,同时也可以监听来自kern的所有日志。
Topic exchange
发送到topic exchange的消息不会拥有一个特定的routing key——它可能有一系列由点分隔的词组成。这些词可以是任意值,但是通常将它设置为与message有一定的联系的单词。就像"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"之类的,你喜欢多少个词组合就设计多少个,routing key最多可达255 bytes。
binding key也必须用如上的routing key的形式。topic exchange背后的逻辑和direct exchange的逻辑很相似——一个包含routing key的message将会被分发到所有匹配的binding key后的queue中。但是,这里有两点需要注意的地方:
*(star)可以替换为任一一个词。
#(hash)可以替换0个或多个词。
如下例子中简单解释一下:
在上图例子中,我们可以发送描述animals的消息到x exchange中,message将使用有3个单词(两个点分隔)组成的routing key进行发送,第一个单词描述的是speed,第二个描述colour,第三个描述species:"<speed>.<colour>.<species>"。
同时创建3条bindings:Q1的binding key为"*.orange.*",Q2的binding key为"*.*.rabbit"和"lazy.#"
这些bindings总结如下:
Q1对animals颜色为orange的感兴趣。
Q2会接收所有关于rabbits和lazy的animals。
message的routing key设置为"quick.orange.rabbit"则会被分发到这两个queue中;设置为"lazy.orange.elephant"也会被分发到两个queue中;设置为"quick.orange.fox"则只会分发到Q1中;设置为"lazy.brown.fox"则只会分发到Q2中;设置为"lazy.pink.rabbit"也只会分发一次到Q2中,尽管这个routing key匹配两个bindings;设置为"quick.brown.fox"的消息由于不匹配任何的binding key,因此该message会被丢弃。
同样,如果我们发送只有一个词或者四个词的routing key,像"orange" 或"quick.orange.male.rabbit"这样的会是什么结果?结果是,同样不匹配,message会被丢弃。像"lazy.orange.male.rabbit"这样的,尽管有四个词组成,但是它匹配"lazy.#",所以会被分发到Q2中。
注:topic exchange非常强大并且可以实现其他exchange的功能。
(1)当一个queue的binding key是"#"(hash)时,这个queue将会接收所有的message,就像fanout exchange一样。
(2)当特殊字符*(start)和#(hash)在binding key中都不使用时,topic exchange 的功能就和direct exchange的功能一样。
实现
topic exchange的用法和direct exchange的用法大同小异。
同样,先看看sender.go
函数severityFrom()进行了调整,即发送message时必须设置routing key的值。
在看看receiver.go
声明exchange和queue
根据命令行参数设置binding key
从queue中接收消息
现在运行两个consumer
在producer端发送消息
有点乱,整理下发送的消息:
(1)producer.exe bad.orange.black 初级赛亚人
(2)producer.exe lazy.orange.* 黑色赛亚人
(3)producer.exe lazy.xxx.xxx 懒人赛亚人
看看两个consumer分别收到了哪些消息
再看看RabbitMQ Server的web监控页面:
这样就可以实现日志不仅按严重等级进行划分,还可以按日志来源,用户等等进行划分。