RabbitMQ 3.11.26 维护版本解读:权限事件修复、AMQP 1.0 告警阻塞与策略诊断新命令
【免费下载链接】rabbitmq-serverOpen source RabbitMQ: core server and tier 1 (built-in) plugins项目地址: https://gitcode.com/gh_mirrors/ra/rabbitmq-server
RabbitMQ3.11.26是3.11.x发布系列的一个维护版本(maintenance release),发布于3.11.x系列生命周期晚期,聚焦于少量关键缺陷修复与可观测性增强。本文以该版本的官方发布说明为主线,结合 rabbitmq-server 仓库中对应模块的源码实现,逐项解析本次修复的技术背景、底层机制与实战验证方式,帮助读者在升级前理解每个变更的实际影响。
版本背景与升级前提
3.11.x 系列的维护状态
3.11.26属于3.11.x发布系列。需要注意的是,该系列已不再受社区支持(community support 已结束),这意味着该版本只包含关键缺陷修复,不会再有新特性加入。如果读者仍在使用3.11.x系列,建议结合自身业务评估升级到仍在支持周期内的版本;若要从3.11.0之前的版本升级,请先阅读 v3.11.0 发布说明 中的升级章节,其中列出了从旧版本升级到 3.11 系列所需的完整步骤与注意事项。
Erlang 版本要求:最低 25
本版本延续了自3.11.0起确立的 Erlang 基线要求:
- 最低支持版本:Erlang/OTP 25;
- 支持上限:
25.3.x; - 硬性约束:在更旧的 Erlang 发行版上,节点将无法启动(nodes will fail to start),这不是降级警告而是启动阻断。
以 Erlang 25 作为新基线带来的收益包括:ARM64 架构上显著改善的性能、全架构下支持火焰图(flame graphs)性能分析,以及 RabbitMQ 3.11 用户可用的最新 TLS 1.3 实现。相关细节可参考官方 RabbitMQ 与 Erlang/OTP 兼容性矩阵。
核心 Broker 修复:topic 权限删除事件类型错乱
问题现象
在删除 topic 权限时,部分场景下会发出错误类型的内部事件:本应发出topic.permission.deleted,实际却发出了permission.deleted。这个差异会影响所有订阅 RabbitMQ 内部事件流(internal events)的下游系统,例如管理插件的事件总线、联邦/Shovel 的状态追踪、以及基于事件做审计或自动化响应的自定义消费者。
事件类型的源码定位
两种事件类型在 rabbit_event_consumer.erl 中有明确的 key 映射定义:
key(permission_created) -> <<"permission.created">>; key(permission_deleted) -> <<"permission.deleted">>; key(topic_permission_created) -> <<"topic.permission.created">>; key(topic_permission_deleted) -> <<"topic.permission.deleted">>;从定义可见,普通权限(user permission)与 topic 权限(topic permission)是两套完全独立的事件类型,语义上不能混用:permission.deleted对应的是用户对 vhost 的configure/write/read三元组权限删除,而topic.permission.deleted对应的是用户在某个 exchange 上的 topic 级读写权限删除。
修复后的正确分发逻辑
问题出现在批量清理权限的场景。在 rabbit_auth_backend_internal.erl 的clear_all_permissions_for_vhost/2中,删除操作会返回一组待清理的记录,随后根据记录类型分发对应事件:
lists:foreach( fun (#topic_permission{topic_permission_key = #topic_permission_key{user_vhost = #user_vhost{username = Username}}}) -> rabbit_event:notify( topic_permission_deleted, [{user, Username}, {vhost, VirtualHost}, {user_who_performed_action, ActingUser}]); (#user_permission{user_vhost = #user_vhost{username = Username}}) -> rabbit_event:notify( permission_deleted, [{user, Username}, {vhost, VirtualHost}, {user_who_performed_action, ActingUser}]) end, Deletions),修复的关键在于按记录类型区分分发:#topic_permission{}记录对应topic_permission_deleted事件,#user_permission{}记录对应permission_deleted事件。此前在某些删除路径(如删除整个 vhost 或批量清空用户权限)中,topic 权限记录被错误地归入permission_deleted分支,导致事件流语义失真。
验证与影响
该问题由社区成员 @bedia 调查确认(GitHub issue #9937)。升级到3.11.26后,可通过订阅内部事件流验证:
rabbitmq-diagnostics log_event_exchange或直接观察事件 key 名称是否与操作类型一致——删除 topic 权限时应收到topic.permission.deleted,删除普通权限时应收到permission.deleted。对依赖事件审计、权限变更自动化同步的系统,该修复保证了事件语义与真实操作严格对齐。
AMQP 1.0 插件修复:资源告警时正确阻塞发布
问题背景
RabbitMQ 的资源告警机制(resource alarms)用于在磁盘空间、内存等资源达到阈值时保护节点稳定。告警生效期间,常规 AMQP 0-9-1 连接会被阻塞(blocked),而本次修复前,AMQP 1.0 连接在告警生效时仍可继续发布消息,导致资源告警的保护语义在 AMQP 1.0 协议上失效(GitHub PR #9955)。
底层实现机制
AMQP 1.0 会话进程在 rabbit_amqp_session.erl 中通过conserve_resources消息处理资源告警:
handle_cast({conserve_resources, Alarm, Conserve}, #state{incoming_window = IncomingWindow0, cfg = #cfg{resource_alarms = Alarms0, incoming_window_margin = Margin0, ... } = Cfg } = State0) -> Alarms = case Conserve of true -> sets:add_element(Alarm, Alarms0); false -> sets:del_element(Alarm, Alarms0) end, {SendFlow, IncomingWindow, Margin} = case {sets:is_empty(Alarms0), sets:is_empty(Alarms)} of {true, false} -> %% Alarm kicked in. %% Notify the client to not send us any more TRANSFERs. ... {true, 0, MaxIncomingWindow}; {false, true} -> %% All alarms cleared. %% Notify the client that it can resume sending us TRANSFERs. {true, MaxIncomingWindow, 0}; _ -> {false, IncomingWindow0, Margin0} end, ...工作机制分为两个层面:
- 本地阻塞:告警生效时,会话的
incoming_window被置为0,同时在cfg.resource_alarms集合中记录告警来源;告警清除时恢复窗口。由于入站窗口为 0,客户端发来的TRANSFER帧(即消息)将不被接受,从协议层面阻断发布。 - 对端协商:会话通过
rabbit_amqp_writer:send_command/3向客户端发送FLOW帧,显式通知对方暂停发送TRANSFER,实现跨网络的流量控制。
会话进程在初始化时通过rabbit_alarm:register/2注册为告警监听者(rabbit_amqp_session.erl),并将resource_alarms维护为sets:set(rabbit_alarm:resource_alarm_source())(rabbit_amqp_session.erl),确保多来源告警(内存、磁盘等)全部清除后才恢复发布。
验证方式
在低磁盘空间或低内存阈值环境下触发告警(可通过临时调低disk_free_limit/vm_memory_high_watermark模拟),观察 AMQP 1.0 客户端在告警期间是否被FLOW帧暂停发送;恢复资源后是否自动恢复发布。此修复使得告警保护语义在所有主流协议(AMQP 0-9-1、AMQP 1.0、MQTT、STOMP)上保持一致。
Grafana Dashboard 增强:全局生产者计数器
本版本为官方 Grafana Dashboard 引入了生产者全局计数器(global counters for producers,GitHub PR #9846,由 CloudAMQP 的 @johanrhodin 贡献,对应 PR #3127)。
该增强的价值在于:此前 Dashboard 上的生产者数量统计通常局限于单节点视角或需按节点切换查看,集群级的生产者总量缺乏统一的可视化入口。新计数器以全局维度汇总集群所有节点上的生产者数量,便于运维人员在 Dashboard 上直接评估整体发布负载分布,无需逐个节点切换视图。该功能属于管理/监控面板层面的增强,不影响 broker 核心行为,升级后刷新 Dashboard 数据源即可看到新指标。
CLI 工具增强:新增list_policies_that_match诊断命令
命令用途
rabbitmq-diagnostics list_policies_that_match [queue name]是3.11.26新增的诊断命令(GitHub PR #9916),核心目的是简化策略冲突(policy conflict)的排障:给定一个队列(或交换机)名称,列出所有与之匹配的策略。由于同一资源上同时匹配多个策略时只有优先级最高的策略会生效,该命令让运维人员一眼看清“哪些策略可能参与竞争、最终谁生效”。
命令定义与参数
命令实现在 list_policies_that_match.ex,关键定义如下:
def scopes(), do: [:diagnostics] def switches(), do: [object_type: :string] def merge_defaults(args, opts) do {args, Map.merge(%{vhost: "/", object_type: "queue"}, opts)} end use RabbitMQ.CLI.Core.RequiresRabbitAppRunning def usage, do: "list_policies_that_match [--object-type <type>] <name>" def help_section(), do: :policies def description(), do: "Lists all policies matching a queue/exchange (only the highest priority policy is active)"从源码可以提取出完整的使用契约:
| 项目 | 说明 |
|---|---|
| 作用域 | diagnostics(即通过rabbitmq-diagnostics调用) |
| 必填参数 | <name>:队列或交换机的名称 |
| 可选参数 | --object-type <queue \| exchange>,默认queue |
| 默认 vhost | /(可通过--vhost覆盖) |
| 前置条件 | 需要 RabbitMQ 应用处于运行状态(RequiresRabbitAppRunning) |
| 输出格式 | 默认PrettyTable表格;支持--formatter json输出结构化结果 |
| 归属帮助分组 | policies策略主题 |
执行流程与底层调用链
命令的执行逻辑(run/2)分两步:
- 资源定位:根据
object_type构造资源描述符——队列通过:rabbit_amqqueue.lookup在目标节点上查询,交换机直接使用构造的资源记录; - 策略匹配:调用 RPC 在目标节点上执行
:rabbit_policy.match_all/1(list_policies_that_match.ex)。
match_all是 RabbitMQ 策略匹配引擎的核心入口(rabbit_policy.erl):
match_all(NameOrQueue) -> match_all(NameOrQueue, list()). match_all(NameOrQueue, Policies) -> match_all(NameOrQueue, Policies, is_policy_applicable).它基于资源名称与 vhost 内的全部策略列表做匹配,is_policy_applicable负责过滤对当前资源类型不适用的策略。策略生效时遵循“优先级最高者胜出”的规则(命令描述中明确提示only the highest priority policy is active),这正是策略冲突排障的核心判定依据。
典型使用场景
# 查看默认 vhost 下队列 q1 匹配到的所有策略 rabbitmq-diagnostics list_policies_that_match q1 # 查看指定 vhost 下交换机 amq.topic 匹配到的策略 rabbitmq-diagnostics list_policies_that_match --object-type exchange --vhost /my-vhost amq.topic # JSON 输出,便于脚本化处理 rabbitmq-diagnostics list_policies_that_match q1 --formatter jsonJSON 输出模式下的响应结构已内建三种形态(见 output/2):
- 无匹配策略:
{"result": "ok", "policies": []}; - 对象不存在:
{"result": "error", "message": "object (queue, exchange) not found", "policies": []}; - 正常匹配:
{"result": "ok", "policies": [策略列表]}。
对于“队列行为异常但不知道是哪个策略导致”的场景,该命令比逐一执行rabbitmqctl list_policies再手工比对名称模式要高效得多,直接给出与目标资源相关的候选集合,再结合优先级字段即可快速定位生效策略。
依赖升级与源码获取
本版本没有任何依赖升级(Dependency Upgrades: None in this release),因此对于关心依赖面变动的生产环境来说,升级风险面进一步收窄。
关于源码获取有一个重要提醒:发布说明明确指出,若要获取整个发行版的源码,应下载名为rabbitmq-server-3.11.26.tar.xz的归档包,而不要使用 GitHub 自动生成的源码 tarball——后者不包含完整的打包脚本与依赖结构,无法直接用于构建完整的发行版。
小结
3.11.26作为 3.11 系列晚期的维护版本,变更面小而精准:
- 核心 Broker:修复 topic 权限删除时内部事件类型错乱(
permission.deleted→topic.permission.deleted),保证事件流语义准确; - AMQP 1.0 插件:资源告警生效时通过窗口归零 +
FLOW帧对端协商正确阻塞发布,补齐跨协议告警语义; - Grafana Dashboard:新增集群级生产者全局计数器,强化发布负载的可观测性;
- CLI:新增
list_policies_that_match诊断命令,显著简化策略冲突排障流程。
对仍在3.11.x系列的用户,建议在充分评估 Erlang 25 基线(最低25.0、最高25.3.x)与 3.11 系列社区支持已结束的前提下,审慎规划升级路径;对事件审计、AMQP 1.0 流量治理与策略管理有强依赖的环境,本版本修复直接提升了这三条路径的可靠性。
【免费下载链接】rabbitmq-serverOpen source RabbitMQ: core server and tier 1 (built-in) plugins项目地址: https://gitcode.com/gh_mirrors/ra/rabbitmq-server
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考