在上一教程中,我们改进了日志记录系统。 我们没有使用只能进行虚拟广播的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. Linux安装配置JDK与卸载

    最近在Linux系统部署门户,安装Oracle,导入dmp,JDK等等,遇到一大堆问题,解决后特有一番小小成就感,哇哈哈!在这里记录一下遇到问题: 官网下载JDK压缩包( .tar.gz ):http ...

  2. MyBatis项目配置案例详解与Web下的增删改查实现[附项目源码]

    MyBatis项目案例 项目图示: 项目源码地址:https://github.com/JluTiger/mybatispro 1.项目功能 项目案例:后台管理系统用户数据维护平台 所有用户数据查询 ...

  3. border-radius后面写px/rem与百分比有什么区别?

    首先百分比,表示的是设置50%表示的是圆是弧度,设置px/rem,是表示你想要变圆弧的半径是多少

  4. spring boot 之注册

    注册数据库 使用spring boot 之登录笔记  的数据库 在server 层 User create(String username, String password, String email ...

  5. MySQL5.7授权用户远程访问

    做个记录,每次弄环境的时候,特别是弄mysql环境,时不时都要用到下面的命令 命令如下: grant all privileges on *.* to 'root'@'%' identified by ...

  6. Ubuntu+QEMU+Xv6环境搭建

    操作系统:Ubuntu 16.04 32位 虚拟机:VMware 模拟器:QEMU 之前有一台centos 64位虚拟机,使用源码安装配置环境,出了一些列问题,最终环境都已经配好了,也能够在qemu上 ...

  7. java输出程序运行时间

    做了一个MapReduce的小练习,想测试一下程序运行时间: 代码: long start = System.currentTimeMillis(); /*运行的程序主体*/ long end = S ...

  8. 系统假死——系统频繁Full gc问题分析

    主要可能的原因: 1,eden区太小,eden和survivor默认比例是8:12,old区太小,新生代和老年代的比例也可以调节的.3,是否程序会分配很多短期存活的大对象,程序本身是否有问题? 进入老 ...

  9. 前端 MV*框架的意义

    早期前端都是比较简单,基本以页面为工作单元,内容以浏览型为主,也偶尔有简单的表单操作,基本不太需要框架. 随着 AJAX 的出现,Web2.0的兴起,人们可以在页面上可以做比较复杂的事情了,然后前端框 ...

  10. ping 域名