浅谈Go与RabbitMQ(一)

237 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

今天来学习如何用Go使用RabbitMQ,跟着我的步伐来一起学习吧!

安装RabbitMQ

在学习RabbitMQ之前,先要安装它,这里介绍通过Docker容器来安装,在Win10环境下安装Docker Destop 下载定制,按照提示一步一步安装,需要在本机上开启虚拟功能

image.png

开启虚拟功能的命令:

  1. 启用适用于 Linux 的 Windows 子系统 dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
  2. 启用Windows虚拟机功能 dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
  3. 将WSL2设置为默认版本 wsl --set-default-version 2
  4. 打开电脑端的Microsoft Store,安装Linux子系统,如下图所示

image.png

安装镜像

Docker Hub中拉取最新的RabbitMQ镜像:

docker pull rabbitmq(不带管理界面,需要手动安装,后续会介绍)
或者 docker pull rabbitmq:3.9.26-management

启动容器: docker run -d --hostname localhost --name rabbitmq -p 15672:15672 -p 5672:5672 rabbitmq

  • --hostname:指定容器主机名称
  • --name:指定容器名称-p:将mq端口号映射到本地
  • -p:指定服务运行的端口(5672:应用访问端口;15672:控制台Web端口号);

image.png

启动之后访问RabbitMQ Management,在浏览器中输入http://localhost:15672会出现无法访问的情况, 需要进入容器内部,手动打开Web管理界面

进入RabbitMQ容器:

rabbitmq替换为自己的容器名或者id

docker exec -it rabbitmq /bin/bash

然后运行下面命令

rabbitmq-plugins enable rabbitmq_management

出现下面内容表示打开成功 image.png

最后输入账号密码: 默认是admin

image.png

点击Channel会遇到Stats in management UI are disabled on this node问题

因为前面拉取的镜像不带后面不带management,启动rabbitmq后是会报错的,需要再手动安装; 所以推荐直接拉取后面带management版本的,例如:docker pull rabbitmq:3.9.26-management

cd /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector = false > management_agent.disable_metrics_collector.conf
exit
重启容器

到此就安装成功了,显示效果如下:

image.png

RabbitMQ的入门

概念

RabbitMQ是一个消息代理:它是一个中间服务者,负责接收和转发消息

RabbitMQ:只是接收、存储和转发二进制数据块--各种消息,而不去处理数据

发送消息:对应生产者,用来产生数据

image.png

队列:是RabbitMQ内部的存储数据的名称,队列只受到主机内存和磁盘大小的限制,实际上就是一个大容量的缓冲区,很多个生产者可以向一个队列中发消息(n:1),许多消费者也可以尝试从一个队列接收数据

image.png

接收消息:对应消费者,等待接收数据

image.png

编写"Hello World"

在下图中,Producer是我们的生产者,Consumer是我们的消费者,中间的框是消息缓冲区image.png

使用go get 安装amqp协议

go get github.com/streadway/amqp

发送者

先建立一个socket连接,并为我们处理协议版本协商和认证等,接下来,我们创建一个通道,这个通道用于提供发送数据所需的API,接着还需要声明要发送到的队列信息。

// 处理错误返回信息
func DoError(err error, msg string) {
   if err != nil {
      log.Fatalf("%s:%s", msg, err)
   }
}
func main() {   
   conn, err := amqp.Dial("amqp://admin:admin@localhost:5672/")
   DoError(err, "Failed connect to RabbitMQ!")
   defer conn.Close()
   ch, err := conn.Channel()
   DoError(err, "Failed to open a channel")
   defer ch.Close()
   queue, err := ch.QueueDeclare(
        "YYQQ", // name
        false,  // durable
        false,  // delete when unused
        false,  // exclusive
        false,  // no-wait
        nil,    // arguments
   )
   DoError(err, "Failed to declare a queue")

   content := "I am a student"
   err = ch.Publish("", queue.Name, false, false,
      amqp.Publishing{
         ContentType: "text/plain",
         Body:        []byte(content),
      })
   DoError(err, "Failed to publish a message")
}

接受者

我们打开一个连接和一个通道,并声明要消耗的队列。这里的声明要和send发布到的队列匹配。

package main

import (
   "github.com/streadway/amqp"
   "log"
)

func DoError(err error, msg string) {
   if err != nil {
      log.Fatalf("%s:%s", msg, err)
   }
}
func main() {
   conn, err := amqp.Dial("amqp://admin:admin@localhost:5672/")
   DoError(err, "Failed to connect to RabbitMQ")
   defer conn.Close()

   ch, err := conn.Channel()
   DoError(err, "Failed to open a channel")
   defer ch.Close()

   queue, err := ch.QueueDeclare(
      "YYQQ", // name
      false,  // durable
      false,  // delete when unused
      false,  // exclusive
      false,  // no-wait
      nil,    // arguments
   )
   DoError(err, "Failed to declare a queue")

   content, err := ch.Consume(queue.Name, // queue
      "",    // consumer
      true,  // auto-ack
      false, // exclusive
      false, // no-local
      false, // no-wait
      nil,   // args
   )
   DoError(err, "Failed to register a consumer")
   var wait chan struct{}
   go func() {
      for msg := range content {
         log.Printf("Received a message %s", msg.Body)
      }
   }()
   <-wait

}

运行两个脚本

go run receive.go
go run send.go

得到的结果如下:

image.png

image.png

总结

今天浅谈了Go与RabbitMQ(一),还有很多相关的知识后面会继续深入,对于刚入门go语言的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!