RabbitMQ_Routing

本节内容我们将对发布订阅增加一个特性:订阅子集。比如我们将一些危险的错误消息保存进硬盘中,同时在控制台仍然能够读取所有的消息

Bingings

上一节内容我们将队列跟交换器进行binging:

err = ch.QueueBind(
q.Name, // queue name
"", // routing key
"logs", // exchange
false,
nil)

一个binging是将交换器跟队列进行关联,可以简单理解为,绑定好的队列只会接收来自这个交换器的消息

Bindings能够携带一个额外的参数:routing_key,为了避免跟Channel.Publish中的参数混淆我们称这个routing_key为binding key。所以我们可以创建一个binding:

err = ch.QueueBind(
q.Name, // queue name
"black", // routing key
"logs", // exchange
false,
nil)

binding key的含义取决交换类型,像之前我们使用的fanout类型就完全忽略了binding key的价值

Direct exchange

上一节中我们的发布订阅模式是将所有的消息广播给消费者,接下来我们进行扩展:允许根据消息的严重性过滤消息。举个例子,对于严重性错误的消息我们直接写硬盘,对于一般的提醒消息或日志则不需要浪费硬盘空间

我们之前使用的fanout交换类型则不具备这些灵活操作,它只能够将消息不加过滤的进行广播。想要达到上面的灵活性我们使用direct交换模式来替代fanout,它能够将消息传递到binding key跟routing key完全匹配的队列

如上图所示,direct类型的交换器绑定了两个队列,第一个队列使用了绑定键是orange,第二个队列使用了两个绑定键,一个是black,另外一个是green

在这样的设置中,使用路由键orange发布到交换器的消息将被路由到队列Q1,使用路由键black或者green则会被路由到队列Q2,其他的消息则会被丢弃

我们也可以使用同一个绑定键来绑定交换器跟不同队列,在这种情况下,direct模式跟fanout有点相似,使用路由键black发布到交换器的消息将被路由到队列Q1跟Q2

接下来我们来实现以下配置的消息系统:

完整的代码如下所示:

emit_log_direct脚本

package main

import (
"fmt"
"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_direct", // name
"direct", // 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_direct", // 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 = "info"
} else {
s = os.Args[1]
}
return s
}

receive_logs_direct脚本

package main

import (
"fmt"
"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_direct", // name
"direct", // 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 usused
true, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") if len(os.Args) < 2 {
log.Printf("Usage: %s [info] [warning] [error]", os.Args[0])
os.Exit(0)
}
for _, s := range os.Args[1:] {
log.Printf("Binding queue %s to exchange %s with routing key %s",
q.Name, "logs_direct", s)
err = ch.QueueBind(
q.Name, // queue name
s, // routing key
"logs_direct", // 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_direct.go info warning error
go run receive_logs_direct.go warning error
go run emit_log_direct.go error "Run. Run. Or it will explode."

Go RabbitMQ(四)消息路由的更多相关文章

  1. 关于rabbitmq的消息路由的同步问题

    http://www.cnblogs.com/me-sa/archive/2012/11/12/rabbitmq_ram_or_disk_node.html我是看了上面的博客明白了一些原理的,我之前一 ...

  2. RabbitMQ Routing 消息路由

    上篇文章中,我们构建了一个简单的日志系统.接下来,我们将丰富它:能够使用不同的severity来监听不同等级的log.比如我们希望只有error的log才保存到磁盘上. 1. Bindings绑定 上 ...

  3. .Net RabbitMQ之消息通信 构建RPC服务器

    1.消息投递服务 RabbitMQ是一种消息投递服务,怎么理解这句话呢?即RabbitMQ即不是消息的生产者,也是消息的消费者.他就像现实生活中快递模式,消费者在电商网站上下单买了一件商品,此时对应的 ...

  4. 四种途径提高RabbitMQ传输消息数据的可靠性(一)

    前言 RabbitMQ虽然有对队列及消息等的一些持久化设置,但其实光光只是这一个是不能够保障数据的可靠性的,下面我们提出这样的质疑: (1)RabbitMQ生产者是不知道自己发布的消息是否已经正确达到 ...

  5. RabbitMQ(4) 未路由的消息、TTL和死信

    未路由的消息 当生产这发送的消息到达指定的交换器后,如果交换器无法根据自身类型.绑定的队列以及消息的路由键找到匹配的队列,默认情况下消息将被丢弃.可以通过两种方式 处理这种情况,一是在发送是设置man ...

  6. rabbitmq高级消息队列

    rabbitmq使用 什么是消息队列 消息(Message)是指在应用间传送的数据.消息可以非常简单,比如只包含文本字符串,也可以很复杂,可以包含嵌入对象. 消息队列是一种应用间的通信方式,消息发送后 ...

  7. RabbitMQ(四):RPC的实现

    原文:RabbitMQ(四):RPC的实现 一.RPC RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. ...

  8. RabbitMQ(三):消息持久化策略

    原文:RabbitMQ(三):消息持久化策略 一.前言 在正常的服务器运行过程中,时常会面临服务器宕机重启的情况,那么我们的消息此时会如何呢?很不幸的事情就是,我们的消息可能会消失,这肯定不是我们希望 ...

  9. RabbitMQ 与 AMQP路由

    概述 RabbitMQ(MQ 为 MessageQueue) 是一个消息队列,主要是用来实现应用程序的异步和解耦,同时起到消息缓冲.消息分发作用 消息队列 消息(Message)是指应用间传送的数据, ...

  10. 【RabbitMQ学习之二】RabbitMQ四种交换机模式应用

    环境 win7 rabbitmq-server-3.7.17 Erlang 22.1 一.概念1.队列队列用于临时存储消息和转发消息.队列类型有两种,即时队列和延时队列. 即时队列:队列中的消息会被立 ...

随机推荐

  1. struts2拦截器demo

    按照网上的一些资料配置的,期间也出现过几个错误. 其中有个错误,是关于struts.xml里面package配置的问题,因为里面的几个标签是有顺序的. 顺序是: result-types interc ...

  2. GlusteFS 二

    通过heketi提供的RestfullApi来管理 Gluster,进而与kubernetes集成.将gluster作为kubernetes的数据存储 1 安装 安装gluster 参见 Gluste ...

  3. svn: Can't convert string from 'UTF-8' to native encoding: 解决办法

    在linux中,svn co 或 svn up 时有中文文件名的文件的话,可能会报下面的错: [root@linkea-dev-srv1 ~]# svn upsvn: Can't convert st ...

  4. Javascript设计模式理论与实战:适配器模式

    有的时候在开发过程中,我们会发现,客户端需要的接口和提供的接口发生不兼容的问题.由于特殊的原因我们无法修改客户端接口.在这种情况下,我们需要适配现有接口和不兼容的类,这就要提到适配器模式.通过适配器, ...

  5. 疑难杂症--在Windows Server 2008 R2上运行SQL Server 2008情况下,CPU过多导致的问题

    64位的Windows7和Windows Server 2008 R2为了能够在一台机器上,支持超过64个逻辑CPU, 引入了Processor Group这个概念.Processor Group会把 ...

  6. 不错的Django博客

    https://blog.csdn.net/chengqiuming/article/category/8453874 杜塞的个人网站 https://www.dusaiphoto.com/ 追梦人物 ...

  7. SQL Union 和Union All 的区别

    Union与Union All的区别 如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字.union(或称为联合)的作用是将多个结果合并 ...

  8. openvswitch dpdk

    作者:张华  发表于:2016-04-07版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) 硬件要 ...

  9. django系列5.5--分组查询,聚合查询,F查询,Q查询,脚本中调用django环境

    一.聚合查询 aggregate(*args, **args) 先引入需要的包,再使用聚合查询 #计算所有图书的平均价格 from django.db.models import Avg Book.o ...

  10. C - Oil Deposits(dfs)

    点击打开链接 Oil Deposits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...