zoukankan      html  css  js  c++  java
  • Go RabbitMQ(四)消息路由

    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."
    
  • 相关阅读:
    Net EF框架+ MySql示例
    Net EF框架+ MySql示例
    C#中读写INI配置文件
    C#中读写INI配置文件
    C#中读写INI配置文件
    IntelliJ IDEA 常用快捷键和设置
    IntelliJ IDEA 常用快捷键和设置
    C++STL_max
    出错啦!
    枝晶生长的宏微观模型
  • 原文地址:https://www.cnblogs.com/develop-SZT/p/10706590.html
Copyright © 2011-2022 走看看