在 FreeBSD 容器上运行 RabbitMQ 集群

我真的很喜欢那种小而简单、专注做好一件事并且做得非常好的专用解决方案——也许是因为我太喜欢 UNIX 了。这种理念的好例子是 Minio 对象存储,它实现了 S3 协议,支持分布式集群、纠删码,并内置了 Web 界面,还有许多其他特性——我曾在《Distributed Object Storage with Minio on FreeBSD》一文中介绍过。

RabbitMQ 是又一个这样的例子——它大概是目前最流行的 AMQP 协议实现之一——同样带有小巧、精致的 Web 界面。但它和 Minio 的区别在于“力量”。Minio 的 Web 界面非常基础、面向用户,大多数管理和配置任务都需要通过 CLI 完成。Minio 的 Web 界面主要提供创建/删除 buckets、上传/下载文件等功能。而 RabbitMQ 的 Web 界面则非常强大,一旦启用,你几乎不再需要命令行了,所有事情都可以通过 Web 界面完成。

rabbitmq-logo.png

和 ActiveMQ、Apache Kafka 等其它消息系统相比,根据 Google Trends 的趋势来看,RabbitMQ 非常流行。

rabbitmq-trends.jpg

今天我想向你展示在 FreeBSD 容器上构建一个带有镜像队列的高度冗余 RabbitMQ 集群的消息系统。

在 FreeBSD 提供的所有虚拟化方式中(VirtualBox / Bhyve / QEMU / Jail / Docker),我选择了最轻量的 FreeBSD 容器 —— Jail :🙂:

图例依旧保持不变。

host 系统上以 root 用户执行的命令:

host 系统上以 普通用户 执行的命令:

rabbitX Jail 中执行的命令:

Jail 配置

首先我们将创建用于本次部署的基础 Jail。host 系统与这些 Jail 容器 都使用 FreeBSD 11.2-RELEASE 系统。

我们现在已经有了 2 个空的、干净的 Jail。

接下来要把这些 Jail 的配置加入 /etc/jail.conf 文件中。

因为我使用的是笔记本作为 Jail 的宿主机,所以 Jails 将会绑定无线网卡 wlan0,并使用 192.168.43.10X 这些地址。同时我也添加了 10.0.0.10X 这组地址,主要是为了撰写本文时操作更方便。

这就是配置完成后的 /etc/jail.conf 文件的样子。

现在我们可以启动这些 Jail 了。

Jail 已正常运行。

现在是时候给 Jail 添加 DNS 服务器,以便它们能够访问互联网。

现在我们将把软件包源从 'quarterly' 切换到 'latest'

安装 RabbitMQ 安装

现在我们可以安装包 RabbitMQ 了。

让我们验证包 RabbitMQ 是否安装成功。

配置 RabbitMQ

接下来我们将在 Jail 中配置 /etc/hosts 文件。

……再简单验证。

由于我们已经安装了包 RabbitMQ,现在需要启用并启动它。

如我们所见,需要在每个 Jail 的 /etc/rc.conf 文件中设置 rabbitmq_enable=YES

现在我们可以在 Jail 中启动 RabbitMQ 了。

现在我们有四个 RabbitMQ 实例已经启动并运行。

默认启用的插件列表:无。

RabbitMQ 插件

现在是时候启用 Web 界面插件了。

现在我们已经在每个 RabbitMQ FreeBSD Jail 中启用了 Web 界面插件。

大写的 ‘E’ 表示这是我们主动启用的插件,而小写的 ‘e’ 表示该插件仅作为其他我们请求启用的插件的依赖而被启用。

现在——为了创建集群——我们需要这些 RabbitMQ 实例共享相同的 ERLANG cookie。在 FreeBSD 系统上,ERLANG cookie 位于 /var/db/rabbitmq/.erlang.cookie

我们需要先停止 RabbitMQ,以便更改 ERLANG cookie。

接下来在每个 FreeBSD Jail 上设置相同的 ERLANG cookie。

……现在我们需要再次启动它们。

快速验证一下。

RabbitMQ 管理用户

现在我们将在 RabbitMQ 实例中创建管理用户 admin

我们现在应该可以登录 http://192.168.43.101:15672/(或者 http://10.0.0.101:15672/)的 RabbitMQ 管理页面了。

01-rabbitmq-login.png

登录后,将显示给你实用的 RabbitMQ 仪表板。

02-rabbitmq-dashboard.png

RabbitMQ 集群设置

接下来我们将创建 RabbitMQ 集群。

首先,我们需要停止 RabbitMQ 的“应用程序”,以便加入集群。

现在我们已经形成了两节点的 RabbitMQ 集群。接下来我们将其重命名为 cluster

下面是在 Web 界面中查看我们集群的样子。

08-rabbitmq-cluster.png

RabbitMQ 高可用策略

要在 RabbitMQ 中实现 高可用(镜像)队列,需要创建 Policy(策略)。我们将声明 Policy ha,它匹配名称以 ha- 前缀开头的队列,从而将这些队列配置为在集群中的两个节点上镜像。

创建该 Policy 的命令如下:

……或者,你也可以使用 Web 界面来创建该策略。

无论使用哪种方法,最终都会得到所需的 Policy ha,如下所示。

03-rabbitmq-policy.png

发送消息到队列

现在我们已经有了两节点的 RabbitMQ 集群,并且为名称以 ha- 前缀开头的队列启用了高可用功能。接下来我们将测试 RabbitMQ 设置,使用 send.go 脚本创建并发送消息到队列——正如你可能猜到的,这个脚本是用 Go 语言编写的。我们需要在 host 系统上安装 Go 语言。

安装 Go 语言

这是 send.go 脚本——我们将使用它向 ha-default 队列发送 10 条消息。它基于教程 RabbitMQ Hello World

接下来我们将运行它。

我们缺少 Go 语言的包 amqp

需要从页面 https://github.com/streadway/amqp 下载。我们将通过下载整个 ZIP 包的方式获取它。

我们还需要确保 PATHGOPATH 配置正确。为此,需要将它们写入你的交互式 shell 配置文件中。

现在我们可以继续向队列发送消息了。

ha-default 队列已创建并发送了 10 条消息。

04-rabbitmq-queue

现在我们需要从队列中“接收”这些消息,这时 receive.go 脚本就派上用场了。它同样基于教程 RabbitMQ Hello World

这是运行后的输出。该程序会一直运行,直到你使用 CTRL-C 快捷键手动结束它。

如果你仔细查看源码,你可能已经注意到,我是在 rabbit1 节点(10.0.0.101)“发送”消息,而在 rabbit2 节点(10.0.0.102)“接收”这些消息的。

简单基准测试

接下来我们将进行简单的基准测试:保持 receive.go 脚本运行,同时修改 send.go 脚本的 for 循环,发送 100000 条消息。

……现在开始发送消息。

这个简单基准测试的结果如下。

05-rabbitmq-benchmark.png

在两个 FreeBSD Jails 内,这个 RabbitMQ 集群实例大约可以处理每秒 4000-5000 条消息。

高可用性测试

现在我们将测试 RabbitMQ 集群的高可用性。

目前 ha-default 队列在 rabbit1 节点上。接下来我们将停止 rabbit1 Jail,观察 RabbitMQ Web 界面的反应。

我们的 ha-default 队列在几秒钟内切换到了 rabbit2 节点 —— 高可用功能按预期工作。

06-rabbitmq-ha-node-fail.png

接下来启动 rabbit1 Jail,以恢复冗余。

07-rabbitmq-ha-node-back.png

ha-default 队列恢复了冗余,显示 +1 标记,但仍然位于 rabbit2 节点。

……最后一点小庆祝——这是我博客的第 50 篇文章(不包含 Valuable News 系列) :🙂:

更新 1 – 本月 RabbitMQ 动态

文章 RabbitMQ Cluster on FreeBSD Containers 被收录在 This Month in RabbitMQ – July 2019 中。

感谢提及!

更新 2 – 降低 RabbitMQ CPU 使用率

Felix EhlersTwitter 所报告,设置变量 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+sbwt none" ,可以降低 RabbitMQ 的 CPU 使用率。

最后更新于

这有帮助吗?