在上一教程中,我们改进了日志记录系统。 我们没有使用只能进行虚拟广播的fanout交换器,而是使用直接交换器,并有可能选择性地接收日志。

尽管使用直接交换改进了我们的系统,但它仍然存在局限性-它不能基于多个条件进行路由。

在我们的日志记录系统中,我们可能不仅要根据严重性订阅日志,还要根据发出日志的源订阅日志。 您可能从syslog unix工具中了解了这个概念,该工具根据严重性(info / warn / crit ...)和工具(auth / cron / kern ...)路由日志。

这将为我们提供很大的灵活性-我们可能只想听来自“ cron”的严重错误,也可以听“ kern”的所有日志。

为了在日志系统中实现这一点,我们需要学习更复杂的topic交换器。

Topic交换器

发送到主题交换的消息不能具有任意的routing_key-它必须是单词列表,以.分隔。 这些词可以是任何东西,但是通常它们指定与消息相关的某些功能。 一些有效的路由关键示例:“ stock.usd.nyse”,“ nyse.vmw”,“ quick.orange.rabbit”。 路由密钥中可以包含任意多个单词,最多255个字节。

绑定键也必须采用相同的形式。 topic交换器背后的逻辑类似于direct交换器的逻辑-使用特定路由键发送的消息将被传递到所有使用匹配绑定键绑定的队列。 但是,绑定键有两个重要的特殊情况:

  • *(星号)可以代替一个单词。

  • #(哈希)可以替代零个或多个单词。

在一个示例中最容易解释这一点:

在此示例中,我们将发送所有描述动物的消息。 将使用包含三个词(两个点)的路由键发送消息。 路由键中的第一个单词将描述速度,第二个描述颜色,第三个描述物种:“ ..”。

我们创建了三个绑定:Q1与绑定键“ * .orange。*”绑定,Q2与“ * . * .rabbit”和“ lazy.#”绑定。

这些绑定可以总结为:

  • Q1对所有橙色动物都感兴趣。
  • Q2想知道有关兔子的一切,以及有关懒惰动物的一切。

路由键设置为“ quick.orange.rabbit”的消息将传递到两个队列。 消息“ lazy.orange.elephant”也将发送给他们两个。 另一方面,“ quick.orange.fox”将仅进入第一个队列,而“ lazy.brown.fox”将仅进入第二个队列。 即使“ lazy.pink.rabbit”与两个绑定匹配,也只会传递到第二个队列一次。 “ quick.brown.fox”与任何绑定都不匹配,因此将被丢弃。

如果我们违约并发送一个或四个单词的消息,例如“ orange”或“ quick.orange.male.rabbit”,会发生什么? 好吧,这些消息将不匹配任何绑定,并且将会丢失。

另一方面,“ lazy.orange.male.rabbit”即使有四个单词,也将匹配最后一个绑定,并将其传送到第二个队列。

Topic交换器功能强大,可以像其他交流一样进行。

当队列用“#”(哈希)绑定键绑定时,它将接收所有消息,而与路由键无关,就像在fanout交换器中一样。

所有代码

我们将在日志记录系统中使用topic交换器。 我们将从一个可行的假设开始,即日志的路由键将包含两个词:“ .”。

# 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
}

获取所有日志

#shell 1
go run receive_logs_topic.go "#"

要从设施“ kern”接收所有日志:

#shell 1
go run receive_logs_topic.go "kern.*"

或者,如果您只想听听“critical”日志:

#shell 1
go run receive_logs_topic.go "*.critical"

您可以创建多个绑定:

#shell 1
go run receive_logs_topic.go "kern.*" "*.critical"

并发出带有路由键“ kern.critical”的日志:

#shell 1
go run emit_log_topic.go "kern.critical" "A critical kernel error"

RabbitMQ官方教程五 Topic(GOLANG语言实现)的更多相关文章

  1. RabbitMQ官方教程四 Routing(GOLANG语言实现)

    在上一教程中,我们构建了一个简单的日志记录系统. 我们能够向许多消费者广播日志消息. 在本教程中,我们将向其中添加功能-我们将使仅订阅消息的子集成为可能. 例如,我们将只能将严重错误消息定向到日志文件 ...

  2. RabbitMQ官方教程三 Publish/Subscribe(GOLANG语言实现)

    RabbitMQ官方教程三 Publish/Subscribe(GOLANG语言实现) 在上一个教程中,我们创建了一个工作队列. 工作队列背后的假设是,每个任务都恰好交付给一个worker处理. 在这 ...

  3. RabbitMQ官方教程二 Work Queues(GOLANG语言实现)

    RabbitMQ官方教程二 Work Queues(GOLANG语言实现) 在第一个教程中,我们编写了程序来发送和接收来自命名队列的消息. 在这一部分中,我们将创建一个工作队列,该队列将用于在多个wo ...

  4. RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe)

    原文:RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  5. 第 五 课 golang语言变量

    1 变量三种声明: (第一种的var和类型都是多余: 第二种最简洁,但是第二种只能用在函数中,不能是全局变量的声明)        第一种: var v_name v_type(注意顺序) v_nam ...

  6. RabbitMQ官方教程一Hello World(GOLANG语言实现)

    介绍 RabbitMQ是消息中间件:它接受并转发消息. 您可以将其视为邮局系统:将要发送的邮件放在邮箱中时, 可以确保邮递员最终将邮件传递给收件人. 以此类推,RabbitMQ是一个邮箱,一个邮局和一 ...

  7. RabbitMQ+PHP教程

    RabbitMQ+PHP 教程一(Hello World) RabbitMQ+PHP 教程二(Work Queues) RabbitMQ+PHP 教程三(Publish/Subscribe) Rabb ...

  8. 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange

    如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...

  9. OpenGL官方教程——着色器语言概述

    OpenGL官方教程——着色器语言概述 OpenGL官方教程——着色器语言概述 可编程图形硬件管线(流水线) 可编程顶点处理器 可编程几何处理器 可编程片元处理器 语言 可编程图形硬件管线(流水线) ...

随机推荐

  1. 边框图片border-image

    一.定义: 在内容变化的容器里使用,边框自动填充,由于浏览器的兼容问题,没有广泛使用 border-image属性是速记属性用于设置 border-image-source, border-image ...

  2. 表述数据的手段——json

    一.JSON 语法规则 在 JS 语言中,一切都是对象.因此,任何支持的类型都可以通过 JSON 来表示,例如字符串.数字.对象.数组等.但是对象和数组是比较特殊且常用的两种类型: 对象表示为键值对 ...

  3. RookeyFrame 线上 添加Model

    线上添加好了模块,会在本地生成几个文件 类文件:Rookey.Frame.Web\Config\TempModel\Order_File.code DLL文件:Rookey.Frame.Web\bin ...

  4. 数据结构实验之排序七:选课名单 (SDUT 3404)

    #include <stdio.h> #include <string.h> #include <stdlib.h> struct node { char data ...

  5. SSM 整合 ehcache spring 配置文件报错

    添加 <!-- end MyBatis使用ehcache缓存 --> <cache:annotation-driven cache-manager="cacheManage ...

  6. php 运算符的优先级

    由上到下,依次递减,同行优先级相同. 结合方向 运算符 附加信息 无 clone new clone 和 new 左 [ array() 右 ** 算术运算符 右 ++ -- ~ (int) (flo ...

  7. ERROR 1067 (42000): Invalid default value for 'time'

    修改sql_mode,去掉NO_ZERO_IN_DATE,NO_ZERO_DATE这两个参数 查看 root@:: [hmda]> show variables like 'sql_mode'; ...

  8. [luogu 5024] 保卫王国

    Problem Here Solution 这大概是一篇重复累赘的blog吧. 最小权覆盖集=全集-最大权独立集 强制取或不取,可以通过将权值修改成inf或者-inf 然后就用动态dp的套路就行了 动 ...

  9. namenode 优化 mv慢的问题

    问题现象 问题描述 公司业务程序需求每30分钟mv 一万多个文件,如果三十分钟之内当前的文件内容没有全部移动,程序报错并且停止. 分析 通过分析,发现在启动balancer和不启动balancer的情 ...

  10. Linux下CFD-Post视图透明的解决方法

    今天发生了一件很搞笑的事情,想用CFD-Post对计算结果做后处理,打开CFD-Post之后,背景居然是透明的,见图 做起后处理来完全看不清楚 下面是解决办法,很简单,步骤如下: 在终端中输入 sud ...