Go RabbitMQ (一)
- 生产者:生产者是负责发送消息的
- 队列:队列是RabbitMQ用来存储消息的,受主机内存和磁盘大小的限制,本质上是一个消息的缓冲区。生产者可以将消息发送至队列中,消费者可以从队列中接收到消息
- 消费者:消费者是用来等待接收消息
生产者,消费者,代理可以驻留在不同主机或同一主机,一个应用可以是生产者也可以是消费者
第一部分 常用操作函数
生产者
1.连接RabbitMQ
conn,err := amqp.Dial("amqp://guest:guest@localhost:5672/")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
RabbitMQ的连接已经为我们抽象了socket的连接,同时为我们处理了协议版本号和身份认证等等
2.创建通道
ch,err := conn.Channel()
if err != nil {
log.Fatal(err)
}
defer ch.Close()
在使用其他API完成任务的时候我们首先通过以上方式创建通道
3.声明队列并发送数据
在开始发送消息之前我们首先应该声明一个队列。声明队列之后我们就可以将消息发送至队列当中
q, err := ch.QueueDeclare(
"hello", // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
说明: 其中durable设为true则queue持久化,否则不会做持久化。
if err != nil {
log.Fatal(err)
}
body := "Hello World!"
err = ch.Publish(
"", // exchange
q.Name, // routing key
false, // mandatory
false, // immediate
amqp.Publishing {
ContentType: "text/plain",
Body: []byte(body),
})
if err != nil {
log.Fatal(err)
}
说明:
其中amqp.Publishing的DeliveryMode如果设为amqp.Persistent则消息会持久化。
需要注意的是如果需要消息持久化Queue也是需要设定为持久化才有效
队列的声明是一个幂等性操作,如果不存在该队列的话则会创建。此处注意,如果队列存在,修改了队列参数并不会影响已经存在的队列,并且会返回错误。消息内容是一个字节数组,所以我们必须进行编码
接收者:
连接,创建通道,队列
在接收端我们同样需要像发送端一样连接RabbitMQ,创建通道后再创建队列,注意此处队列的创建是跟发送端的队列完全匹配的。队列在接收端也创建是因为我们接收端有可能比发送端先启动,所以为了保证我们要消费的队列存在我们在此处也进行创建
1.消费消息
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
if err != nil {
log.Fatal(err)
}
forever := make(chan bool)
go func() {
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
}
}()
log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
第二部分 消费者消息应答模式
1.
接收消息
msgs, err := ch.Consume(
q.Name,
"MsgWorkConsumer",
false, //Auto Ack
false,
false,
false,
nil,
)
其中Auto ack可以设置为true。如果设为true则消费者一接收到就从queue中去除了,如果消费者处理消息中发生意外该消息就丢失了。
如果Auto ack设为false。consumer在处理完消息后,调用msg.Ack(false)后消息才从queue中去除。即便当前消费者处理该消息发生意外,只要没有执行msg.Ack(false)那该消息就仍然在queue中,不会丢失。
生成的Queue在生成是设定的参数,下次使用时不能更改设定参数,否则会报错