简单模式
生产者的消息被负载均衡到各个消费者去,一条消息只会被一个消费者消费,不会产生一条消息重复消费的问题
rabbitmq的数据源格式
amqp://user:pass@IP:5672/VirtualHost
RabbitMq结构体
type RabbitMq struct { conn *amqp.Connection channel *amqp.Channel //队列名称 QueueName string //交换机 Exchange string //key Key string MqUrl string }
创建RabbitMq实例
错误处理函数failOnErr是在有错误的时候打印后面的参数和错误信息
func NewRabbitMq(queueName, exchange, key string) *RabbitMq { rabbitmq := &RabbitMq{ QueueName: queueName, Exchange: exchange, Key: key, MqUrl: MQURL, } var err error //创建rabbitmq连接 rabbitmq.conn, err = amqp.Dial(rabbitmq.MqUrl) rabbitmq.failOnErr(err, "创建连接错误") rabbitmq.channel, err = rabbitmq.conn.Channel() rabbitmq.failOnErr(err, "获取channel失败") return rabbitmq }
RabbitMq销毁函数
func (r *RabbitMq) Destroy() { r.channel.Close() r.conn.Close() }
以上是RabbitMq模块的基础模块,其他模式都是在以上基础上做扩展开发的
首先我们看Simple简单模式
简单模式下创建rabbitmq实例,只需要传入队列名称
func NewRabbitMqSimple(queueName string) *RabbitMq {
return NewRabbitMq(queueName, "", "")
}
简单模式下生产者代码,
使用channel.QueueDeclare申请队列,然后通过channel.Publish中把消息推送到队列中
func (r *RabbitMq) PublishSimple(message string) {
//1 申请队列,如果队列不存在则申请队列,如果存在则跳过创建,保证队列存在消息能在队列中
_, err := r.channel.QueueDeclare(
//队列名称
r.QueueName,
//是否持久化
false,
//是否自动删除
false,
//是否具有排他性(不常用,消息只对自己账号可见)
false,
//是否阻塞
false,
//额外属性
nil)
if err != nil {
fmt.Printf("queue declare failed, error:%+v\n", err)
return
}
//2发送消息到队列中
r.channel.Publish(
//交换机
"", //简单模式为空
//routingKey
r.QueueName,
//mandatory如果为true会根据exchange类型和routekey规则,
//如果无法找到符合条件的队列就把消息返还给发送者
false,
//immediate如果为true,当exchage发送消息到队列后,
//如果发现队列上没有绑定消费者就把消息返还给发送者
false,
//发送的信息
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(message),
})
}
简单模式下消费者代码
申请channel队列,然后通过channel.Consume获得生产者的消息
func (r *RabbitMq) ConsumeSimple() {
//1 申请队列,如果队列不存在则申请队列,如果存在则跳过创建,保证队列存在消息能在队列中
_, err := r.channel.QueueDeclare(
//队列名称
r.QueueName,
//是否持久化
false,
//是否自动删除
false,
//是否具有排他性(不常用,消息只对自己账号可见)
false,
//是否阻塞false是阻塞
false,
//额外属性
nil)
if err != nil {
fmt.Printf("queue declare failed, error:%+v\n", err)
return
}
//2接收消息
msgs, err := r.channel.Consume(
//队列名称
r.QueueName,
//用来区分多个消费者,为空不区分
"",
//autoAck是否自动应答,如果把消息消费了,主动告诉rabbitmq服务器
true,
//是否具有排他性,只能查看到我自己账号创建的消息,和pulish对应
false,
//noLocal如果设置为true,不能将同一个connection发送的消息,传递给同一个connection中的其他消费者
false,
//是否阻塞,false阻塞
false,
//额外参数
nil)
if err != nil {
fmt.Printf("channel.Consume failed, error:%+v\n", err)
return
}
forever := make(chan bool)
go func() {
for d := range msgs {
//实现我们要处理的逻辑函数
log.Printf("Received a message:%s", d.Body)
}
}()
log.Printf("[*] Waiting for message, exit to press CTRL + C")
<-forever
}
简单模式下使用方法
生产者
package main
import (
"fmt"
"rabbitmq/RabbitMq"
)
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
rabbitmq.PublishSimple("hello imooc")
fmt.Printf("发送成功!\n")
}
消费者
package main
import "rabbitmq/RabbitMq"
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
rabbitmq.ConsumeSimple()
}
生产者把消息("hello imooc")推送到rabbitmq服务器
消费者获取到生产者的消息,并打印
输出结果为:
2019/07/04 11:12:35 [*] Waiting for message, exit to press CTRL + C
2019/07/04 11:12:46 Received a message:hello imooc
rabbitmq简单模式下的工作模式
上面的案例是一对一的模式,如果要使用一对多、多对多的模式,就是在简单模式下多个生产者多个消费者
生产者
package main
import (
"rabbitmq/RabbitMq"
"strconv"
"time"
)
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
for i:=0;i<10;i++ {
rabbitmq.PublishSimple("one hello imooc" + strconv.Itoa(i))
time.Sleep( 100 * time.Millisecond)
}
}
======================================
package main
import (
"rabbitmq/RabbitMq"
"strconv"
"time"
)
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
for i:=0;i<10;i++ {
rabbitmq.PublishSimple("two hello imooc" + strconv.Itoa(i))
time.Sleep( 100 * time.Millisecond)
}
}
消费者
package main
import "rabbitmq/RabbitMq"
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
rabbitmq.ConsumeSimple()
}
==========================================
package main
import "rabbitmq/RabbitMq"
func main(){
rabbitmq := RabbitMq.NewRabbitMqSimple("imoocSimple")
rabbitmq.ConsumeSimple()
}
分析:
多个生产者往同一个队列中推送消息,消费者平均获取各个生产者消息,每个消息只会被消费一次,不会出现重复模式
消费者1输出结果
2019/07/04 11:19:58 [*] Waiting for message, exit to press CTRL + C
2019/07/04 11:20:02 Received a message:one hello imooc1
2019/07/04 11:20:02 Received a message:one hello imooc3
2019/07/04 11:20:02 Received a message:one hello imooc5
2019/07/04 11:20:02 Received a message:one hello imooc7
2019/07/04 11:20:03 Received a message:one hello imooc9
2019/07/04 11:20:04 Received a message:two hello imooc1
2019/07/04 11:20:04 Received a message:two hello imooc3
2019/07/04 11:20:04 Received a message:two hello imooc5
2019/07/04 11:20:05 Received a message:two hello imooc7
2019/07/04 11:20:05 Received a message:two hello imooc9消费者2输出结果
2019/07/04 11:19:55 [*] Waiting for message, exit to press CTRL + C
2019/07/04 11:20:02 Received a message:one hello imooc0
2019/07/04 11:20:02 Received a message:one hello imooc2
2019/07/04 11:20:02 Received a message:one hello imooc4
2019/07/04 11:20:02 Received a message:one hello imooc6
2019/07/04 11:20:02 Received a message:one hello imooc8
2019/07/04 11:20:04 Received a message:two hello imooc0
2019/07/04 11:20:04 Received a message:two hello imooc2
2019/07/04 11:20:04 Received a message:two hello imooc4
2019/07/04 11:20:05 Received a message:two hello imooc6
2019/07/04 11:20:05 Received a message:two hello imooc8