插件开发基础
本指南介绍了 RabbitMQ 插件开发的基础知识。预期读者在阅读本指南之前,已对 RabbitMQ 插件机制有基本了解。
还预期读者对 Erlang 和 OTP 设计原则 有基本了解。
Learn You Some Erlang 是学习 Erlang 和 OTP 的绝佳途径。
为什么要开发插件?
编写 RabbitMQ 插件提供了许多吸引人的可能性:
- 使您的应用程序能够访问 RabbitMQ 内部功能,而这些功能不通过受支持的协议之一暴露。
- 在与代理相同的 Erlang VM 中运行,可以提高某些工作负载的性能。
- 插件可以实现本应由系统中每个应用程序(服务)实现的特性,从而避免重复并减轻维护负担。
为什么不开发插件
与任何插件机制一样,在开发功能时应考虑嵌入其作为插件是否是最合适的途径。您可能不希望将功能开发为插件的一些原因:
- 依赖内部 RabbitMQ API 可能导致您的应用程序在新的 RabbitMQ 版本(包括补丁版本)发布时需要进行更改。如果您可以在不使用 RabbitMQ 内部组件的情况下完成所需工作,那么您的应用程序将具有更强的向前兼容性。
- 编写不佳的插件可能导致整个节点变得不可用或行为异常。
入门
要开发 RabbitMQ 插件,请首先确保满足以下要求:
Erlang.mk 用于构建 RabbitMQ 及其插件。开始编写新插件最简单的方法可能是复制一个现有插件,例如rabbitmq-metronome,如下例所示。
开发期间激活插件
要在开发过程中测试插件,请使用以下 make 目标来启动一个 RabbitMQ 节点,该节点加载并启用了从源代码构建的本地插件。
make run-broker
插件质量提示
编写糟糕的插件可能会对代理的稳定性构成风险。为确保您的插件能够安全运行而不影响 RabbitMQ 核心,强烈建议采用一些安全最佳实践。
- 始终为您的应用程序使用顶级 supervisor。
- 切勿直接启动插件应用程序,而是选择创建一个(可能非常简单的) supervisor,它将防止 Erlang VM 因顶级应用程序崩溃而关闭。
代理和依赖项版本约束
可以使用插件应用程序环境中的 broker_version_requirements 键来指定插件的代理和依赖项版本要求。要求被指定为每个发布系列中的最低版本列表。考虑以下示例:
{application, my_plugin,[
%% ...
{broker_version_requirements, ["3.11.15", "3.10.22"]}
]}
以上要求 RabbitMQ 3.10.x 从 3.10.22 开始,3.11.x 从 3.11.15 开始。请注意,当新的主要和次要(功能)RabbitMQ 版本发布时,插件维护者必须更新列表。
插件可以有依赖项。也可以指定依赖项支持的版本系列。这与上面非常相似,但使用类似字典的数据结构(proplist)。
例如:
{application, my_plugin, [
%% ...
{dependency_version_requirements, [{rabbitmq_management, ["3.11.0", "3.10.22"]}]}
]}
表示插件依赖于 rabbitmq_management 3.10.x 从 3.10.22 开始,以及 3.11.x 系列中的所有版本。
示例插件:Metronome
鉴于没有任何开发指南会缺少“Hello World”示例,以下内容试图提供构建您自己的 RabbitMQ 插件的基础。
以下示例详细说明了如何构建一个简单的插件,该插件的作用类似于节拍器。
每秒,它会将一个路由键形式为 yyyy.MM.dd.dow.hh.mm.ss 的消息发送到一个名为 metronome 的主题交换器(默认)。应用程序可以通过各种路由键将队列绑定到此交换器,以便按固定间隔被调用。例如,要每秒接收一条消息,可以应用 *.*.*.*.*.*.* 的绑定。要每分钟接收一条消息,可以改为应用 *.*.*.*.*.*.00 的绑定。
GitHub 上的 rabbitmq-metronome 仓库包含此插件的代码副本。
下表应解释仓库中各种文件的用途。
| 文件名 | 目的 |
|---|---|
Makefile | 此顶层 Makefile 定义了您的插件名称及其依赖项。名称必须与 Erlang 应用程序名称匹配。依赖项使用 erlang.mk 的变量声明。紧接着,Makefile 包含rabbitmq-components.mk和erlang.mk,以及rabbitmq-plugins.mk,使用 erlang.mk 插件机制。有关这些文件的说明,请参阅下文。 |
erlang.mk | 本地副本erlang.mk。这不是一个纯净的副本,因为 RabbitMQ 依赖于一些在撰写本文时尚未合并到上游的修改。这就是为什么ERLANG_MK_REPO和ERLANG_MK_COMMIT目前被覆盖。 |
rabbitmq-components.mk | 本地副本rabbitmq-components.mk。原始文件位于rabbitmq-common,您的插件将自动依赖它。它包含其他 erlang.mk 扩展和助手,这些必须在erlang.mk包含之前定义。此文件必须与rabbitmq-common保持同步:当它过时时,您将收到以下错误 在这种情况下,只需运行以下命令即可更新您的副本 |
rabbitmq_metronome.schema | 一个 Cuttlefish 配置模式。用于将 配置文件 转换为 RabbitMQ 及其运行时使用的内部格式。 Metronome schema 包含 启用插件后,配置将重新生成。如果插件尚未启用,配置中的插件特定值将导致错误。 有关编写模式文件的更多信息,请参阅 Cuttlefish 文档。 |
src/rabbit_metronome.erl | Erlang“应用程序”行为的实现。它为 Erlang VM 提供了启动和停止插件的手段。 |
src/rabbit_metronome_sup.erl | Erlang“supervisor”行为的实现。监控 worker 进程,并在其崩溃时重新启动它。 |
src/rabbit_metronome_worker.erl | 插件的核心。worker 将在内部连接到代理,然后创建一个每秒触发一次的任务。 |
test/metronome_SUITE.erl | 插件的自动化测试。 |
开发流程
将您的插件克隆到 rabbitmq-server 仓库的 deps 目录中。
git clone https://github.com/rabbitmq/rabbitmq-server.git
cd rabbitmq-server
git clone https://github.com/user/my-rabbitmq-plugin.git deps/my_rabbitmq_plugin
运行 make 来构建插件。
make -C deps/my_rabbitmq_plugin
要启动一个加载了您的 my_rabbitmq_plugin 和 management 插件的节点,请执行以下操作:
make RABBITMQ_ENABLED_PLUGINS='rabbitmq_management my_rabbitmq_plugin' run-broker
为确保新插件已成功运行,请运行以下命令:
rabbitmq-diagnostics status
如果您的插件已成功加载,您应该会在已启用插件列表中看到它。
# => Plugins
# =>
# => Enabled plugin file: /var/folders/gp/53t98z011678vk9rkcb_s6ph0000gn/T/rabbitmq-test-instances/rabbit@warp10/enabled_plugins
# => Enabled plugins:
# =>
# => * rabbitmq_metronome
# => * amqp_client
# => * my_rabbitmq_plugin
要运行 Common Test 测试套件,请使用:
make -C deps/my_rabbitmq_plugin tests
最后,您可以生成一个 .ez 文件,适合随以下内容分发:
make -C deps/my_rabbitmq_plugin DIST_AS_EZS=yes dist
该文件出现在仓库根目录下的plugins目录中。