RabbitMQ Go客户端教程5——topic
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第五篇——topic。
这些教程涵盖了使用RabbitMQ创建消息传递应用程序的基础知识。 你需要安装RabbitMQ服务器才能完成这些教程,请参阅安装指南或使用Docker镜像。 这些教程的代码是开源的,官方网站也是如此。
先决条件
本教程假设RabbitMQ已安装并运行在本机上的标准端口(5672)。如果你使用不同的主机、端口或凭据,则需要调整连接设置。
topic交换器(主题交换器)
发送到topic交换器的消息不能具有随意的routing_key——它必须是单词列表,以点分隔。这些词可以是任何东西,但通常它们指定与消息相关的某些功能。一些有效的routing_key示例:“stock.usd.nyse”,“nyse.vmw”,“quick.orange.rabbit”。routing_key中可以包含任意多个单词,最多255个字节。
绑定键也必须采用相同的形式。topic交换器背后的逻辑类似于direct交换器——用特定路由键发送的消息将传递到所有匹配绑定键绑定的队列。但是,绑定键有两个重要的特殊情况:
*(星号)可以代替一个单词。#(井号)可以替代零个或多个单词。
通过下面这个示例可以很容易看明白这一点:
img
在这个例子中,我们将发送一些都是描述动物的信息。将使用包含三个词(两个点)的路由密钥发送消息。路由键中的第一个单词将描述速度,第二个是颜色,第三个是种类:“<speed>.<colour>.<species>”。
我们创建了三个绑定关系:Q1与绑定键“*.orange.*”绑定,Q2与“*.*.rabbit”和“lazy.#”绑定。
这些绑定可以总结为:
- Q1对所有橙色动物都感兴趣。
- Q2想接收有关兔子(rabbit)的一切消息,以及有关懒惰(lazy)动物的一切消息。
路由键设置为“quick.orange.rabbit”的消息将传递到两个队列。消息“lazy.orange.elephant”也将发送给他们两个。另一方面,“quick.orange.fox”将仅进入第一个队列,而“lazy.brown.fox”将仅进入第二个队列。即使“lazy.pink.rabbit”与两个绑定匹配(匹配Q2的两个绑定),也只会传递到第二个队列一次。 “quick.brown.fox”与任何绑定都不匹配,因此将被丢弃。
如果我们打破约定并发送一个或四个单词的消息,例如“orange”或“quick.orange.male.rabbit”,会发生什么?好吧,这些消息将不匹配任何绑定,并且将会丢失。
另外,“lazy.orange.male.rabbit”即使有四个单词,也将匹配最后一个绑定,并将其传送到第二个队列。
topic交换器
topic交换器功能强大,可以像其他交换器一样运行。
当队列用“
#”(井号)绑定键绑定时,它将接收所有消息,而与路由键无关,就像在fanout交换器中一样。当在绑定中不使用特殊字符“
*”(星号)和“#”(井号)时,topic交换器的行为就像direct交换器一样。
完整示例
我们将在日志记录系统中使用topic交换器。我们将从一个可行的假设开始,即日志的路由键将包含两个词:“<facility>.<severity>”。
该代码与上一教程中的代码几乎相同。
emit_log_topic.go的代码:
package main
import (
"log"
"os"
"strings"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
err = ch.ExchangeDeclare(
"logs_topic", // name
"topic", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange")
body := bodyFrom(os.Args)
err = ch.Publish(
"logs_topic", // exchange
severityFrom(os.Args), // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body),
})
failOnError(err, "Failed to publish a message")
log.Printf(" [x] Sent %s", body)
}
func bodyFrom(args []string) string {
var s string
if (len(args) < 3) || os.Args[2] == "" {
s = "hello"
} else {
s = strings.Join(args[2:], " ")
}
return s
}
func severityFrom(args []string) string {
var s string
if (len(args) < 2) || os.Args[1] == "" {
s = "anonymous.info"
} else {
s = os.Args[1]
}
return s
}
receive_logs_topic.go的代码:
package main
import (
"log"
"os"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
err = ch.ExchangeDeclare(
"logs_topic", // name
"topic", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange")
q, err := ch.QueueDeclare(
"", // name
false, // durable
false, // delete when unused
true, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
if len(os.Args) < 2 {
log.Printf("Usage: %s [binding_key]...", os.Args[0])
os.Exit(0)
}
// 绑定topic
for _, s := range os.Args[1:] {
log.Printf("Binding queue %s to exchange %s with routing key %s",
q.Name, "logs_topic", s)
err = ch.QueueBind(
q.Name, // queue name
s, // routing key
"logs_topic", // exchange
false,
nil)
failOnError(err, "Failed to bind a queue")
}
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto ack
false, // exclusive
false, // no local
false, // no wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() {
for d := range msgs {
log.Printf(" [x] %s", d.Body)
}
}()
log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
<-forever
}
想要接收所有的日志:
go run receive_logs_topic.go "#"
要从“kern”接收所有日志:
go run receive_logs_topic.go "kern.*"
或者,如果你只想接收“critical”日志:
go run receive_logs_topic.go "*.critical"
你可以创建多个绑定:
go run receive_logs_topic.go "kern.*" "*.critical"
并发出带有路由键“kern.critical”的日志:
go run emit_log_topic.go "kern.critical" "A critical kernel error"
你可以自己尝试玩一下这个程序。请注意,代码没有对路由键或绑定键进行任何假设,你可能希望使用两个以上的路由键参数。
(关于emit_log_topic.go和receive_logs_topic.go的完整源代码)
接下来,我们将在教程6中了解如何将往返消息用作远程过程调用。
RabbitMQ Go客户端教程5——topic的更多相关文章
- RabbitMQ Go客户端教程1——HelloWorld
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,共分为六篇,本文是第一篇--HelloWorld. 这些教程涵盖了使用RabbitMQ创建消 ...
- RabbitMQ Go客户端教程3——发布/订阅
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第三篇--发布/订阅. 这些教程涵盖了使用RabbitMQ创建消息传递 ...
- RabbitMQ Go客户端教程6——RPC
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第六篇--RPC. 这些教程涵盖了使用RabbitMQ创建消息传递应用 ...
- RabbitMQ Go客户端教程4——路由
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第四篇--路由. 这些教程涵盖了使用RabbitMQ创建消息传递应用程 ...
- RabbitMQ Go客户端教程2——任务队列/工作队列
本文翻译自RabbitMQ官网的Go语言客户端系列教程,本文首发于我的个人博客:liwenzhou.com,教程共分为六篇,本文是第二篇--任务队列. 这些教程涵盖了使用RabbitMQ创建消息传递应 ...
- SpringBoot系列之RabbitMQ使用实用教程
SpringBoot系列之RabbitMQ使用实用教程 @ 目录 1. 消息队列概述 1.1 MQ的概述 1.2 MQ目的地形式 2. 消息队列实现方式 2.1 常见MQ框架 2.2 MQ实现方式 3 ...
- RabbitMq C# .net 教程
本文转载来自 [http://www.cnblogs.com/yangecnu/p/Introduce-RabbitMQ.html]写的很详细. 文件安装包官方DEMO下载地址是:http://pan ...
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- C#基于RabbitMQ实现客户端之间消息通讯实战演练
一.背景介绍和描述 MQ消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.何时需要消息队列?当你需要使用 ...
随机推荐
- LOJ #6029. 「雅礼集训 2017 Day1」市场 线段树维护区间除法
题目描述 从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落. 有 \(n\) 个商贩,从\(0 \sim n - 1\) 编号,每个商 ...
- git clone克隆github仓库慢,问题解决
导读 转载自:https://www.hangge.com/blog/cache/detail_2670.html 原因 由于国内网络问题,当我们使用 git clone 命令从 github ...
- 程序员注意【自verycd.com的JavaAmg77 】
展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告 走过的路,回忆起来是那么曲折,把自己的一些心得体会分享给程序员兄弟姐妹们,虽然时代在变化,但是很可能你也会走我已经做过的1 ...
- Jenkins - Linux下启动Jenkins报错hudson.WebAppMain#contextDestroyed: Shutting down a Jenkins instance that was still starting up
报错截图 在Linux下直接运行jenkins.war报错,导致启动失败 报错原因 运行端口已被其他进程占用 解决方法 换个启动端口就可以啦!
- Tim Urban:如何选择真正适合你的职业?
Wait But Why是一个专注于写长博客的网站,Tim Urban是网站的创始人之一.Tim Urban专注于写长论文,与时下的轻度阅读完全背道而驰,文章动辄几千甚至上万字,但令人吃惊的是却拥有惊 ...
- Golang 接口型函数和http.Handler接口
一.接口型函数 参考Golang必备技巧:接口型函数 1.原始接口实现 type Handler interface { Do(k, v interface{}) } func Each(m map[ ...
- ELF文件格式内容
在计算机科学中,是一种用于二进制文件.可执行文件.目标代码.共享库和核心转储格式文件. ELF文件组成部分 ELF文件由4部分组成,分别是ELF头(ELF header).程序头表(Program ...
- WPF窗体中嵌入/使用WinForm类/控件(基于.NET Core)
如题,WPF中嵌入WinForm的做法,网络上已经很多示例,都是基于.NET XXX版的. 今天King様在尝试WPF(基于.NET Core 3.1)中加入Windows.Forms.ColorDi ...
- Java POI导入word, 带图片
1.导入文件示例,word中简历表格模板 2.代码示例分两部分,一部分读取图片 /** * 导入word(基本信息,word格式) * @param staffId * @param baseInfo ...
- PL/SQL Developer 13注册码(亲测可用)
product code: 4vkjwhfeh3ufnqnmpr9brvcuyujrx3n3le serial Number: 226959 password: xs374ca