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的主要手段之一.何时需要消息队列?当你需要使用 ...
随机推荐
- MVC中Cookie的用法(二)---CookieHelper
public class CookieHelper { /// <summary> /// 1.1添加Cookie /// </summary> /// <param n ...
- leetcode76set-matrix-zeroes
题目描述 给定一个m*n的矩阵,如果有一个元素是0,就把该元素所在的行和列上的元素全置为0,要求使用原地算法. 拓展: 你的算法有使用额外的空间吗? 一种比较直接的算法是利用O(m,n)的空间,但是这 ...
- mvc SelectList 给下拉框 @Html.DropDownList绑定值
后台代码: public class DropController : Controller { // GET: Drop public ActionResult Index() { List< ...
- CDM 设置 主键自增
一些朋友在用PD建概念模型时,觉得主键无法设置自增,还需要在生成PDM后,单独再设置一次,很麻烦. 自增主键一般都是整形,int ,long 如果我们在CDM建实体模型时,将自增主键设置为Serial ...
- 【webSocket】实现原理
服务端文件: import base64 import hashlib import socket # 将请求头格式化成字典 def get_headers(data): ""&q ...
- 优测 x QTA 兼容性测试全面启动啦
鉴于Android系统开放性开发,以及Android系统在智能机市场的覆盖率超高的特点,APP的兼容性测试需求大幅提升.为迎合市场需求,优测(Utest)与QTA合作,全力打造兼容性测试服务.由优测提 ...
- 【转】CentOS7 64位安装mysql教程
从最新版本的linux系统开始,默认的是 Mariadb而不是mysql!这里依旧以mysql为例进行展示 1.先检查系统是否装有mysql rpm -qa | grep mysql 这里返回空值,说 ...
- Python_字符串处理方法
1.字符串转换 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sStr1 = 'strcpy2' print sStr2 1.字符串复制 #s ...
- BurpSuite 抓安卓app包
认准夜神安卓模拟器,下了几个其他的模拟器都没有代理的功能 一.夜神安卓模拟器设置代理 1.点击右下角的设置 2.点击设置,进入到WIFI连接选项 3.进入列表后,鼠标点击wifi位置,长按左键,会出现 ...
- Hadoop优化之数据压缩
bBHadoop数据压缩 概述 运行hadoop程序时,I/O操作.网络数据传输.shuffle和merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下,这个时候,使用数据压缩可以提高效率 ...