RabbitMQ_Routing

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

Bingings

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

  1. err = ch.QueueBind(
  2. q.Name, // queue name
  3. "", // routing key
  4. "logs", // exchange
  5. false,
  6. nil)

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

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

  1. err = ch.QueueBind(
  2. q.Name, // queue name
  3. "black", // routing key
  4. "logs", // exchange
  5. false,
  6. 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脚本

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "strings"
  7. "github.com/streadway/amqp"
  8. )
  9. func failOnError(err error, msg string) {
  10. if err != nil {
  11. log.Fatalf("%s: %s", msg, err)
  12. }
  13. }
  14. func main() {
  15. conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
  16. failOnError(err, "Failed to connect to RabbitMQ")
  17. defer conn.Close()
  18. ch, err := conn.Channel()
  19. failOnError(err, "Failed to open a channel")
  20. defer ch.Close()
  21. err = ch.ExchangeDeclare(
  22. "logs_direct", // name
  23. "direct", // type
  24. true, // durable
  25. false, // auto-deleted
  26. false, // internal
  27. false, // no-wait
  28. nil, // arguments
  29. )
  30. failOnError(err, "Failed to declare an exchange")
  31. body := bodyFrom(os.Args)
  32. err = ch.Publish(
  33. "logs_direct", // exchange
  34. severityFrom(os.Args), // routing key
  35. false, // mandatory
  36. false, // immediate
  37. amqp.Publishing{
  38. ContentType: "text/plain",
  39. Body: []byte(body),
  40. })
  41. failOnError(err, "Failed to publish a message")
  42. log.Printf(" [x] Sent %s", body)
  43. }
  44. func bodyFrom(args []string) string {
  45. var s string
  46. if (len(args) < 3) || os.Args[2] == "" {
  47. s = "hello"
  48. } else {
  49. s = strings.Join(args[2:], " ")
  50. }
  51. return s
  52. }
  53. func severityFrom(args []string) string {
  54. var s string
  55. if (len(args) < 2) || os.Args[1] == "" {
  56. s = "info"
  57. } else {
  58. s = os.Args[1]
  59. }
  60. return s
  61. }

receive_logs_direct脚本

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "github.com/streadway/amqp"
  7. )
  8. func failOnError(err error, msg string) {
  9. if err != nil {
  10. log.Fatalf("%s: %s", msg, err)
  11. }
  12. }
  13. func main() {
  14. conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
  15. failOnError(err, "Failed to connect to RabbitMQ")
  16. defer conn.Close()
  17. ch, err := conn.Channel()
  18. failOnError(err, "Failed to open a channel")
  19. defer ch.Close()
  20. err = ch.ExchangeDeclare(
  21. "logs_direct", // name
  22. "direct", // type
  23. true, // durable
  24. false, // auto-deleted
  25. false, // internal
  26. false, // no-wait
  27. nil, // arguments
  28. )
  29. failOnError(err, "Failed to declare an exchange")
  30. q, err := ch.QueueDeclare(
  31. "", // name
  32. false, // durable
  33. false, // delete when usused
  34. true, // exclusive
  35. false, // no-wait
  36. nil, // arguments
  37. )
  38. failOnError(err, "Failed to declare a queue")
  39. if len(os.Args) < 2 {
  40. log.Printf("Usage: %s [info] [warning] [error]", os.Args[0])
  41. os.Exit(0)
  42. }
  43. for _, s := range os.Args[1:] {
  44. log.Printf("Binding queue %s to exchange %s with routing key %s",
  45. q.Name, "logs_direct", s)
  46. err = ch.QueueBind(
  47. q.Name, // queue name
  48. s, // routing key
  49. "logs_direct", // exchange
  50. false,
  51. nil)
  52. failOnError(err, "Failed to bind a queue")
  53. }
  54. msgs, err := ch.Consume(
  55. q.Name, // queue
  56. "", // consumer
  57. true, // auto ack
  58. false, // exclusive
  59. false, // no local
  60. false, // no wait
  61. nil, // args
  62. )
  63. failOnError(err, "Failed to register a consumer")
  64. forever := make(chan bool)
  65. go func() {
  66. for d := range msgs {
  67. log.Printf(" [x] %s", d.Body)
  68. }
  69. }()
  70. log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
  71. <-forever
  72. }

使用下面命令运行:

  1. go run receive_logs_direct.go info warning error
  2. go run receive_logs_direct.go warning error
  3. 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. MSP430 G2553 LaunchPad设置GPIO

    一. 背景知识:逻辑运算符的使用 当程序初始化时,对于复位状态有不确定性的寄存器(如PxOUT),建议采用直接赋值:其他情况下最好使用逻辑运算符修改寄存器. 直接赋值 REGISTER = 0b111 ...

  2. 基于Extjs的web表单设计器 第一节

    前面一节介绍了表单设计器的背景和最终的大概样式,本节主要介绍表单设计器的需求及功能设计. 在讲需求之前先明确几个常用的概念: 主表或者卡片表——具有多行多列的一个区域的控件块,如下图所示. 明细表—— ...

  3. Javascript设计模式理论与实战:简单工厂模式

    通常我们创建对象最常规的方法就是使用new关键字调用构造函数,这会导致对象之间的依赖性.工厂模式是一种有助于消除类之间依赖性的设计模式,它使用一个方法来决定要实例化哪一个类.本文详细介绍了简单工厂模式 ...

  4. [javascript][翻译]使用javascript添加css rule

    来杭一周,收获很多,成长很多. 周六在搞一个插件的时候碰到需要动态添加伪元素的需求,搜了一下解决方案,有人用正则写出了读取伪元素的函数:我觉得倒是可以通过注入css rule的方式,来让预留有某些类的 ...

  5. ajax 与 form 提交的区别

    有如下几种区别: 1. Ajax在提交.请求.接收时,都是异步进行的,网页不需要刷新:Form提交则是新建一个页面,哪怕是提交给自己本身的页面,也是需要刷新的: 2. A在提交时,是在后台新建一个请求 ...

  6. ASP.NET MVC 通过ActionFilterAttribute来实现防止重复提交

    实现思想:每个页面打开的时候会在页面的隐藏控件自动生成一个值并将这个值赋值session,当提交方法的时候会在过滤器的时候进行获取session和页面传值过来的隐藏控件的值进行比较,如果值相同的话,重 ...

  7. 基于python 3.5 所做的找出来一个字符串中最长不重复子串算法

    功能:找出来一个字符串中最长不重复子串 def find_longest_no_repeat_substr(one_str): #定义一个列表用于存储非重复字符子串 res_list=[] #获得字符 ...

  8. Javascript实例 -- 计时器, 搜索框,selected联动

    计时器: <body> <input type="text" id="i1"> <input type="button& ...

  9. Python脱产8期 Day15 2019/4/30

    一 生成器send方法 1.send的工作原理# 1.send发生信息给当前停止的yield# 2.再去调用__next__()方法,生成器接着往下指向,返回下一个yield值并停止 2.例: per ...

  10. Hibernate 干货2

    @ORM框架 对象关系映射,用于实现面向对象编程语言里不同系统的数据之间的转换 @实例public void demo01(){  User user = new User();  user.setU ...