今天开始学习消息队列中间件在go语言中的应用,并做了一些简单的记录。
一、拉取镜像
运行docker pull rabbitmq
语句即可在docker中安装拉取一个最新的镜像。当然也可以自己选择一个版本,这里不在赘述。
二、创建容器
使用docker images
我们就可以看到自己的所有docker image ID,我的如下:
我们可以直接执行下面的语句创建一个新的rabbitmq容器并且绑定对应的端口。
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management
复制代码
- --name指定了容器名称
- -d 指定容器以后台守护进程方式运行
- -p指定容器内部端口号与宿主机之间的映射,rabbitMq默认要使用15672为其web端界面访问时端口,5672为数据通信端口
查看容器日志 使用docker logs -f 容器ID
命令可以查看容器日志,我们执行docker logs -f 3ae
命令查看rabbitMq在启动过程中日志
三、访问地址
http://ip地址:15672
,这里的用户名和密码默认都是guest。由于只是作为本地的一个测试,不作为远程访问,便不添加新的账户密码了。
HelloWorld 生产者-消费者
发送
首先,不管是在发送方还是接收方,我们都定义一个辅助函数用于检查每个amqp调用的返回值,如果在连接rabbitMQ或者打开channel的过程出错,都可以及时反馈。
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
复制代码
接着编写消息生产者(发送者)send.go
和我们的消息消费者(接收者)receive.go
。 发布者将连接到RabbitMQ,发送单个消息,然后退出。 在send.go
中,我们需要先导入包:
package main
import (
"log"
"github.com/streadway/amqp"
)
复制代码
然后连接到RabbitMQ服务器
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
复制代码
配置连接套接字,它主要定义连接的协议和身份验证等。接下来,我们创建一个channel来传递消息:
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")
复制代码
接收
以上是消息生产者。消费者需要监听来自RabbitMQ的消息,因此与生产者不同,它需要持续运行以监听消息并将其打印出来 代码
receive.go
具有与send相同的导入包和辅助函数:
package main
import (
"log"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
复制代码
设置与生产者相同,首先打开一个连接和一个Channel,并声明要消费的队列。
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()
q, err := ch.QueueDeclare(
"hello", // name
false, // durable
false, // delete when usused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
复制代码
在这里也做了队列声明。 因为消费者可能在生产者启动前就运行了,所以要确保使用消息之前队列已经存在。 我们即将告诉服务器从队列中传递消息。因为它会异步地向我们发送消息,所以我们将在goroutine中读取来自channel (由amqp :: Consume
返回)的消息。
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("Received a message: %s", d.Body)
}
}()
log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
复制代码
最后分别在两个终端运行发送者和接受者,结果如下:
我们也可以在web管理界面channel中看到数据的情况: