使用Docker容器实现RabbitMQ实例的Docker化
RabbitMQ是一个开源的分布式消息队列,支持许多通信协议。它是一个消息代理,接收来自发送者(生产者)的消息,并将其转发给接收者(消费者)。
这些消息被保存在一个队列中。队列是一个建立在先进先出(FIFO)原则基础上的巨大的消息缓冲区。许多生产者可以向队列提交消息,而消费者可以尝试从这些队列中获取消息。
RabbitMQ 架构和基本组件
RabbitMQ 架构是由生产者和消费者组成的。正如我们所说,生产者是正在发送消息的应用程序或服务。
消费者是将接收消息的应用程序或服务。因此,我们不需要生产者直接调用消费者服务,而是建立另一个服务器,作为两者之间的中介。在这种情况下,我们将有一个 RabbitMQ 服务器。
有一些重要的组件可以促进消费者和生产者之间的 RabbitMQ 消息中介。这些组件是
- 生产者(发布者) - 一个应用程序或服务,它将消息发布到 RabbitMQ 服务器。
- Exchange - 它充当消息过滤器。它接收来自生产者的消息,并使用路由规则将它们发布到队列中,以便将它们发送给消费者。
例如,以典型的电话交换机为例,用于呼叫路由。当消息到达电话交换机时,Exchange 确定特定消息的目标消费者并进行相应的路由。
- 队列 - 一个存储已发布消息的 RabbitMQ 缓冲区。
- 消费者 - 从 RabbitMQ 服务器队列中读取消息的应用程序或服务。

下面是一个用户发送请求(消息)以创建一个 PDF Web 应用程序(生产者)的简单场景

为了使四个组件有效地进行通信,以下属性在确定消息目的地时将是至关重要的。
-
消息 - 这是生产者和消费者正在交换的数据或信息。发布者产生的每个消息都有两个主要部分。就是说。
- 消息头 - 定义了消息头的属性。
- 消息体--被共享的消息内容。
根据消息共享模式,一条消息可以有发布、确认、未确认、重新交付、准备和接收属性。
-
路由键 - 一个 RabbitMQ 可以有许多消息队列。在这种情况下,每个产生的消息都需要有一个虚拟地址密钥,交易所将使用该密钥来确定消息应被路由到哪个队列。该虚拟地址被称为路由密钥。
-
绑定(绑定密钥)--将队列链接到交易所。交易所使用绑定和路由密钥来确定哪个消息属于哪个队列。

- 交换类型 - 有四种消息交换类型。
- 主题 - 根据路由键中的模式来路由消息。例如,根据另一个因素(如销售点)分发特定于地理位置的数据。

- Fanout - 将消息路由到与之绑定的所有队列,路由键被忽略。Fanout Exchange 的一个优秀示例是群组聊天。RabbitMQ 将使用此方案将消息分发到该特定组的不同参与者。

- 直接 - 基于消息路由键将消息传递给队列。该队列必须与路由密钥相同。它适用于向个人发送消息时--例如,向特定地理位置的个人发送通知。

- 头信息 - 它忽略了路由键,并查看与信息一起发送的头信息。

RabbitMQ 如何工作
RabbitMQ被用作消息代理,以实现高级消息排队协议(AMQP)。一个完整的AMQP有三个主要组成部分,一个经纪人、一个消费者和一个生产者。
当在生产者和消费者之间交换消息时,消息不会直接发送到队列中。它们首先通过一个交换器(在经纪人中),将它们重定向到它们的目标队列。
生产者将生产消息,然后将其发布在一个交易所中。每条消息都有其路由密钥。
现在,交易所确保该消息最终出现在正确的队列中。交易所要确保消息进入正确的队列,取决于几件事,包括交易所的类型,它规定了路由规则、路由密钥和报头属性的数量。
把交换想象成一个邮件投递员,确保信息最终进入正确的箱子。在这种情况下,他需要正确的地址来确保邮件在正确的人手中。
在此示例中,路由规则、路由密钥和报头属性充当了消息的地址。RabbitMQ 将它们用作不同交换类型的绑定规则,以根据队列绑定键确定哪个消息链接到哪个队列。
一旦消息进入正确的队列,消费者就可以请求他想消费的消息。
综上所述。
- 一个生产者将消息发布到一个交易所。
- 绑定规则(路由密钥)使用绑定密钥将交易所与队列连接起来。
- 一个消费者从队列中接收消息。
- 消费者将消息发回给经纪人,并通知服务器它收到了消息。因此,经纪人可以从队列中删除该消息。

为什么我们需要 RabbitMQ(一个消息代理)?
当你有一个服务对服务通信的微服务应用程序时,即服务A和B通信时,服务A将同步地直接调用服务B。
在同步场景的服务中,A必须等待服务B的响应。如果服务B需要很长的时间来响应,这个连接就有可能超时。
为了获得成功的响应,服务A必须多次重试。如果服务B死亡或崩溃,通信就会丢失,并且没有消息被交换。
服务 A 只在有 RabbitMQ 服务器的情况下产生消息,而 RabbitMQ 服务器将把它们保存在队列中。因此,每当服务 A 想联系服务 B 时,它不会直接向服务 B 发送消息。
每当服务 B 想获得由服务 A 发送的消息时,它将去队列中获得该消息。由于该消息已被发布和保存,如果B第一次没有得到该消息,它将重试并再次得到它,因为它在队列中仍然可用。消息队列的优势在于。
- 一个服务不直接依赖于另一个服务。
- 你可以扩大生产者的规模以产生更多的消息。
- 你可以扩大多个消费者的规模,直接从队列中访问消息。
- 为你的应用程序增加弹性。如果一个服务出现故障,其他服务将不会受到直接影响。
使用 docker 容器设置 RabbitMQ
现在我们了解了 RabbitMQ 的工作原理及其重要性,让我们使用 Docker 容器设置 RabbitMQ 服务器。
我们将在本地计算机上使用 Docker 设置并启动一个简单的 RabbitMQ 实例,以及 RabbitMQ 管理 UI 和基本管理员功能。
我假设您已经具备 Docker 的基本知识以及如何使用 docker-compose。此外,请确保您在本地计算机上安装了 Docker。
最后,运行docker version ,检查Docker是否被成功安装。
我们将使用 docker compose.yml 来设置一个 RabbitMQ 实例。因此,请继续并在您想要的目录中创建一个 docker-compose.yml 文件。
- 首先,定义您要运行的 docker-compose 版本。
version: "3.8"
- 添加 RabbitMQ 服务、RabbitMQ 属性以及您希望容器运行的环境。
services:
rabbitmq3:
- 设置容器名称。
container_name: "rabbitmq"
- 添加要从 Docker 集线器中提取的容器镜像。有不同的标签可用于 RabbitMQ 镜像。
在这里,我们拉出带有管理标签的镜像,因为我们想访问 RabbitMQ 管理 UI。RabbitMQ 管理 UI 将使我们能够管理 RabbitMQ 队列、通道、队列和交换。
image: rabbitmq:3-management
- 添加 RabbitMQ 容器环境。我们正在设置 RabbitMQ 用户名和密码,我们将使用它们来登录和访问 RabbitMQ 管理 UI。
environment:
- RABBITMQ_DEFAULT_USER=myuser
- RABBITMQ_DEFAULT_PASS=mypassword
- 定义将在 Docker 上运行并对外公开容器的容器端口。该端口将暴露其容器,以便我们可以通过浏览器访问它。
ports:
# AMQP protocol port
- '5672:5672'
# HTTP management UI
- '15672:15672'
现在您的 docker-compose.yml 文件已被设置为用 Docker 容器来启动这个 RabbitMQ 实例。
version: "3.8"
services:
rabbitmq3:
container_name: "rabbitmq"
image: rabbitmq:3.8-management-alpine
environment:
- RABBITMQ_DEFAULT_USER=myuser
- RABBITMQ_DEFAULT_PASS=mypassword
ports:
# AMQP protocol port
- '5672:5672'
# HTTP management UI
- '15672:15672'
现在让我们通过运行命令docker-compose up 来测试该组合文件。运行docker-compose up 将下载并设置 Rabbit MQ 容器。

如果您打开您的 Docker 引擎,您将看到 RbbitMQ 容器已设置并运行。

如果你在浏览器上打开http://localhost:15672/ ,你将能够访问管理 Ui,现在你可以使用 docker-compose 设置的用户名和密码来登录。

现在你可以看到RabbitMQ实例已经启动并运行。

一个简单的测试案例
现在您可以开始添加队列和发布消息。让我们来测试一下。转到队列选项卡并添加一个新队列;将其称为test-queue 。
在交换标签上,添加一个新的交换,称之为test-exchange 。选择交换类型为直接。

点击并打开添加的test-exchange 。

现在我们将为新创建的队列创建一个绑定。向下滚动并从这个交换中添加绑定。这里我们将添加我们创建的队列的名称。同时,添加路由键为green 。



让我们通过向test-exchange 发布消息来测试这个方案。这里我们测试的是直接交换用例。所以在发布消息部分,添加路由密钥为white ,并在有效载荷部分添加一条消息。

直接交换的概念表明,消息是根据消息的路由密钥传递到队列中的。
在这种情况下,test-queue 被分配了带有green 路由键的消息。使用white 作为路由键将导致这个消息不能被路由到这个队列。所以,让我们试着用white 作为路由键来发布这个消息。

你可以看到,这个消息被发布了,但没有被路由到test-queue 。现在用green 作为路由键,尝试同样的方法。

这条消息被发布并传递到了test-queue 。因此,如果你前往标签队列,选择test-queue ,并点击获取消息按钮,你可以看到消息被路由到队列中。

总结
我们已经讨论了 RabbitMQ 的基础知识。
RabbitMQ 支持多种[编程语言],您可以使用它来开发跨语言的消息传递应用程序。它支持流行的语言,如[Java]、[Javascript]、[Python]、[PHP]、[C 和 C++]、[Golang] 以及[更多]。
继续尝试使用您选择的编程语言来实现 RabbitMQ 的概念。
你可以使用和学习的其他消息传递队列(broker)包括[Kafka]、[Redis]、[Beanstalk]和[IBM MQ]。