中间件介绍
MQ:消息队列。消息中间件是利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
abbitMQ:abbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求可能比较低了。
AMQP协议
AMQP是一种协议,是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。这使得实现了AMQP的provider天然性就是跨平台的。
6大模型
RabbitMQ有6大模型,分别是Helloworld,Workqueues,Publish/Subscribe,Routing,Topics,RPC等6模型
Helloworld
生产者生成消息到队列中,消费者进行消费,直连单点模式。
生产者:
声明连接对象
var ProductMQ *amqp.Connection
声明通道
ch, err := ProductMQ.Channel()
创建队列
q, err := ch.QueueDeclare("hello", // 队列名字
false, // 是否持久化,
false, // 不用的时候是否自动删除
false, // 用来指定是否独占队列
false, // no-wait
nil, // 其他参数
)
发布消息
body := "Hello World!"
err = ch.Publish(
"", // 交换机
q.Name, // 队列名字
false, // 是否强制性
// 当mandatory标志位设置为true时,如果exchange根据自身类型和消息routeKey无法找到一个符合条件的queue,那么会调用basic.return方法将消息返回给生产者
// 当mandatory设置为false时,出现上述情形broker会直接将消息扔掉
false, //当immediate标志位设置为true时,如果exchange在将消息路由到queue(s)时发现对于的queue上么有消费者,那么这条消息不会放入队列中。当与消息routeKey关联的所有queue(一个或者多个)都没有消费者时,该消息会通过basic.return方法返还给生产者
// 是否立刻
/**
概括来说,mandatory标志告诉服务器至少将该消息route到一个队列中,否则将消息返还给生产者;immediate标志告诉服务器如果该消息关联的queue上有消费者,则马上将消息投递给它,如果所有queue都没有消费者,直接把消息返还给生产者,不用将消息入队列等待消费者了。
**/
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body), // 发送的消息
})
消费者 声明通道
ch, err := ConsumerMQ.Channel()
创建队列
q, err := ch.QueueDeclare(
"hello",
false,
false,
false,
false,
nil,
)
读取队列消息
msgs, err := ch.Consume(
q.Name,
"",
true,
false,
false,
false,
nil,
)
消费者端需要一直监听,所以我们要用一个for循环+channel去阻塞主进程,使得主进程一直处于监听状态
forever := make(chan bool)
go func() {
for d := range msgs {
fmt.Printf("Received a message: %s", d.Body)
}
}()
fmt.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
Work Queues
让多个消费者绑定到一个队列,共同消费队列中的消息
生成消息在队列中
body := "Hello World! "
for i := 0; i < 10; i++ {
msg := strconv.Itoa(i)
err = ch.Publish(
"", // 交换机
q.Name, // 队列名字
false, // 是否强制性
false, // 是否立刻
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body+msg), // 发送的消息
})
}
Publish/Subscribe
此模型。又称广播 在广播模式下,消息发送流程如下:
可以有多个消费者 每个消费者有自己的queue(队列) 每个队列都要绑定到Exchange(交换机) 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。 交换机把消息发送给绑定过的所有队列 队列的消费者都能拿到消息。实现一条消息被多个消费者消费
生产者:
声明交换机
_ = ch.ExchangeDeclare("logs", "fanout", true, false, false, false, nil)
生产消息:
_ = ch.Publish("logs", "", false, false,
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body),
})
消费者:
声明交换机
_ = ch.ExchangeDeclare("logs", "fanout", true, false, false, false, nil, )
声明队列
q, _ := ch.QueueDeclare("", false, false, true, false, nil, )
绑定交换机
_ = ch.QueueBind(q.Name, "", "logs", false, nil, )
消费消息
msgs, _ := ch.Consume(q.Name, "", true, false, false, false, nil, )