• go-rabbitmq


    rabbitmq文档地址 https://www.rabbitmq.com/getstarted.html

    示例代码地址 https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go

    只有队列 没有交换机 没有路由的生产者

    文档地址 https://www.rabbitmq.com/tutorials/tutorial-one-go.html

    package main
    
    import (
    	"log"
    
    	"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://admin:123456@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()
    
    	q, err := ch.QueueDeclare(
    		"hello", // name
    		false,   // durable
    		false,   // delete when unused
    		false,   // exclusive
    		false,   // no-wait
    		nil,     // arguments
    	)
    	failOnError(err, "Failed to declare a queue")
    
    	body := "Hello World!"
    	err = ch.Publish(
    		"",     // exchange
    		q.Name, // 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)
    }
    
    

    运行结果

    ╭─mac@macdeMacBook-Pro /www/go/rabbit ‹master*› 
    ╰─$ go run main.go
    2021/02/28 11:29:43  [x] Sent Hello World!
    
    

    生产订阅模式的生产者

    fanout模式

    该模式下 消息会发给交换机,交换机会发送给所有绑定的队列 发送的时候,不需要关系路由和队列

    如果没有队列绑定到交换,则消息将丢失,但这对我们来说是可以的。如果没有消费者在听,我们可以放心地丢弃该消息。

    代码如下

    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",   // name
    		"fanout", // 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", // exchange
    		"",     // 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) < 2) || os.Args[1] == "" {
    		s = "hello"
    	} else {
    		s = strings.Join(args[1:], " ")
    	}
    	return s
    }
    

    消费者

    代码 需要指定交换机和队列,不需要路由

    package main
    
    import (
    	"log"
    
    	"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",   // name
    		"fanout", // type
    		true,     // durable
    		false,    // auto-deleted
    		false,    // internal
    		false,    // no-wait
    		nil,      // arguments
    	)
    	failOnError(err, "Failed to declare an exchange")
    
    	q, err := ch.QueueDeclare(
    		"test1",    // name
    		true, // durable
    		false, // delete when unused
    		false,  // exclusive
    		false, // no-wait
    		nil,   // arguments
    	)
    	failOnError(err, "Failed to declare a queue")
    
    	err = ch.QueueBind(
    		q.Name, // queue name
    		"",     // routing key
    		"logs", // 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
    }
    

    direct交换模式

    直接交换背后的路由算法很简单-一条消息进入绑定键与该消息的路由键完全匹配的队列 。

    生产者代码

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

    运行

    go run emit_log_direct.go route1 2021/02/28 12:43:13 [x] Sent hello

    注意 交换机会新建,但是不会自动新建队列和路由

    这里要路由队列和交换机一一对应才能发送到对应的队列里面

    消费者代码

    消费者会自动创建和绑定路由

    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(
    		"lll",    // name
    		true, // durable
    		false, // delete when unused
    		false,  // 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)
    		fmt.Println(q.Name)
    		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
    }
    

    topic模式

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

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

    为了在我们的日志系统中实现这一点,我们需要了解更复杂的主题交换。

    话题交流

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

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

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

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

    这些绑定可以总结为:

    • Q1对所有橙色动物都感兴趣。
    • 第2季想听听有关兔子的一切,以及有关懒惰动物的一切。

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

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

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

    话题交流

    主题交流功能强大,可以像其他交流一样进行。

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

    当在绑定中不使用特殊字符“ * ”(星号)和“ # ”(哈希)时,主题交换的行为就像直接的一样。

    生产者代码

    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
    }
    

    go run emit_log_topic.go "a.we" “错误”

    绑定路由为a.*时候 会发送过去 b.c时候不会

    消费者代码

    package main
    
    import (
    	"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_topic", // name
    		"topic",      // type
    		true,         // durable
    		false,        // auto-deleted
    		false,        // internal
    		false,        // no-wait
    		nil,          // arguments
    	)
    	failOnError(err, "Failed to declare an exchange")
    
    	q, err := ch.QueueDeclare(
    		"topic2",    // name
    		true, // durable
    		false, // delete when unused
    		false,  // exclusive
    		false, // no-wait
    		nil,   // arguments
    	)
    	failOnError(err, "Failed to declare a queue")
    
    	if len(os.Args) < 2 {
    		log.Printf("Usage: %s [binding_key]...", 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_topic", s)
    		err = ch.QueueBind(
    			q.Name,       // queue name
    			s,            // routing key
    			"logs_topic", // 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
    }
    
  • 相关阅读:
    Artifact Project3:war exploded: Error during artifact deployment. See server log for details.
    Struts2的OGNL表达式语言
    java空指针异常:java.lang.NullPointException
    两天撸一个天气应用微信小程序
    Graves of the Internet
    JavaScript并非“按值传递”
    js实现黑客帝国二进制雨
    JavaScript“并非”一切皆对象
    纯CSS打造银色MacBook Air(完整版)
    element-ui中轮播图自适应图片高度
  • 原文地址:https://www.cnblogs.com/brady-wang/p/14458759.html
Copyright © 2020-2023  润新知