跳至主内容
版本:4.3

策略

概述

尽管 RabbitMQ 的大部分配置都在 配置文件 中,但有些配置项并不适合通过配置文件来管理

  • 如果它们需要在集群中的所有节点上保持一致
  • 如果它们需要在运行时发生变更

RabbitMQ 中的这些值存储为 运行时参数 (runtime parameters)。策略就是运行时参数使用方式的一个示例。

本指南主要介绍策略 (Policies) 和操作员策略 (Operator policies)。

为什么存在策略

提示

策略是一种声明式机制,用于配置队列、流和交换机的特定属性。它们是为那些可以在运行时更改的参数而设计的。

注意

由于队列(流)类型是在声明时设定的,且无法更改,因此策略在设计上不能用于配置队列类型。若要指定队列(流)类型,请使用 可选参数 (optional arguments)

策略是一种声明式的、以 虚拟主机 (virtual host) 为作用域的机制,用于动态地 [重] 配置队列、交换机、流以及某些插件(即 联合 (federation))的 可选参数

策略与应用程序设置的可选参数之间的区别

在解释什么是策略以及如何使用它们之前,有必要说明一下引入它们的原因。

除了强制属性(如 durableexclusive)之外,RabbitMQ 中的队列和交换机还有 可选参数,有时称为 x-arguments

这些参数由客户端在声明队列(交换机)时提供,用于控制各种可选功能,例如 队列长度限制TTL

在 RabbitMQ 支持的某些协议中,客户端控制的属性通常工作良好,但它们不够灵活:以这种方式更新 TTL 值或镜像参数需要更改应用程序、重新部署以及重新声明队列(涉及删除操作)。此外,没有办法为一组队列和交换机批量控制额外的参数。引入策略就是为了解决上述痛点。

策略通过名称(使用正则表达式模式)匹配一个或多个队列,并将其定义(可选参数映射)附加到匹配队列的 x-arguments 中。换句话说,通过策略可以一次性配置多个队列的 x-arguments,并通过更新策略定义来一次性更新它们。

在现代版本的 RabbitMQ 中,可以通过策略控制的功能集与可以通过客户端提供参数控制的功能集并不完全相同。

策略的工作原理

策略的关键属性包括

  • 名称 (name):可以是任何名称,但建议使用不带空格的 ASCII 名称
  • 模式 (pattern):匹配一个或多个队列(交换机)名称的正则表达式。可以使用任何正则表达式。
  • 定义 (definition):一组键/值对(类似于 JSON 文档),将被注入到匹配的队列和交换机的可选参数映射中
  • 策略优先级 (policy priority):用于确定当多个策略匹配其名称时,应将哪个策略应用于队列或交换机

策略会自动匹配交换机和队列,并帮助决定它们的行为。每个交换机或队列最多只能有一个策略匹配(请参阅下文的 组合策略定义),每个策略随后会将一组键值对(策略定义)注入到匹配的队列(交换机)中。

策略可以仅匹配特定类型的队列、所有队列、仅交换机,或所有队列和交换机。这是在创建策略时通过 apply-to 标志控制的。

策略可以随时更改。当更新策略定义时,它对匹配的交换机和队列的影响将被重新应用。通常这是瞬间完成的,但对于非常繁忙的队列,可能需要一点时间(例如几秒钟)。

策略在每次创建交换机或队列时都会进行匹配和应用,而不仅仅是在创建策略时。

策略可用于配置

以及其他功能。

无法使用策略设置的内容

某些可选参数无法通过策略进行配置。它们控制着无法在运行时更改的各种设置。两个关键示例是

这些值故意不能通过策略配置:它们的值在队列声明时是固定的。

如何定义策略

定义策略的示例如下

rabbitmqctl set_policy federate-me \
"^federated\." '{"federation-upstream-set":"all"}' \
--priority 1 \
--apply-to exchanges
危险

当多个策略匹配一个实体且它们的优先级相等时,生效的策略将不确定地选择。应注意各种策略使用的优先级,以避免此类情况发生

这将为虚拟主机 "/" 中名称以 "federated." 开头的所有交换机,将值 "all" 与键 "federation-upstream-set" 进行匹配。

"pattern" 参数是用于匹配交换机或队列名称的正则表达式。

如果多个策略可以匹配给定的交换机或队列,则优先级最高的策略生效。

"apply-to" 参数可以是以下之一

  • "exchanges",仅应用于交换机
  • "queues",应用于所有类型的队列,包括流
  • "classic_queues",仅应用于经典队列
  • "quorum_queues",仅应用于仲裁队列
  • "streams",仅应用于流
  • "all",应用于所有交换机和队列(包括流)

"apply-to""priority" 设置是可选的。默认值分别为 "all""0"

策略优先级

策略模式与交换机和队列名称进行匹配,以确定应将哪种策略(如果有)注入到匹配的队列(交换机)的 可选参数 中。

最多有一个策略匹配队列或交换机。由于多个策略可以匹配单个名称,因此需要一种机制来解决这种策略冲突。此机制称为策略优先级。每个策略都有一个与其关联的数字优先级。此优先级可以在声明策略时指定。如果未显式提供,则使用 0(非常低)。

重要

最多有一个策略匹配队列或交换机。匹配的策略随后按优先级排序,优先级最高的策略生效。

值越高表示优先级越高:优先级为 10 的策略将覆盖优先级为 8 的策略,两者都将覆盖默认的优先级 0。

危险

当多个策略匹配一个实体且它们的优先级相等时,生效的策略将不确定地选择。应注意各种策略使用的优先级,以避免此类情况发生

匹配的策略随后按优先级排序,优先级最高的策略生效。

当多个策略匹配一个实体且它们的优先级相等时,生效的策略将不确定地选择。应注意各种策略使用的优先级,以避免此类情况发生

组合策略定义

在某些情况下,我们可能希望将多个策略定义应用于一个资源。例如,我们可能需要一个队列既是联合的,又具有消息 TTL。在任何给定时间,最多有一个策略应用于资源,但我们可以在该策略中应用多个定义。

提示

另请参阅下文的 更新策略

联合策略定义需要指定一个 上游集合 (upstream set),因此我们需要在定义中使用 federation-upstream-set 键。另一方面,要将某些队列定义为启用 TTL,我们也需要定义与 TTL 相关的键。策略定义只是一个 JSON 对象,可以在同一个策略定义中组合多个键。

这是一个例子。

rabbitmqctl set_policy ttl-fed \
"^tf\." '{"federation-upstream-set":"all", "message-ttl":60000}' \
--priority 1 \
--apply-to queues

通过这样做,所有匹配模式 "^tf\." 的队列都将应用 "federation-upstream-set" 和策略定义。

删除策略

可以使用 rabbitmqctl clear_policyrabbitmqadmin policies delete 删除策略。

rabbitmqctl clear_policy --vhost "vh.1" "policy.name"

声明覆盖(临时覆盖策略)

rabbitmqadmin 可用于声明覆盖或覆盖策略。

这是一种应用于与现有策略相同对象集(例如队列)但包含不同定义和更高优先级(准确地说是 +100)的策略。

覆盖策略旨在短期使用,例如在 蓝/绿集群迁移 的最后阶段启用队列联合。

以下示例使用 rabbitmqadmin policies declare_override 覆盖名为 "pol.1" 的策略,并注入与 队列联合 相关的键。

rabbitmqadmin --vhost 'vh.1' policies declare_override --name 'pol.1' --definition '{"federation-upstream-set": "all"}'

覆盖将原始策略名称前缀为 "overrides.",并将结果截断为 255 字节(策略名称长度限制)。

删除覆盖策略与删除任何其他策略没有区别。使用 rabbitmqadmin policies delete --name [override policy name]

rabbitmqadmin --vhost 'vh.1' policies delete --name 'overrides.pol.1'

声明全覆盖策略 (Blanket Policy)

全覆盖策略是涵盖所有未被其他策略覆盖的队列的策略。根据定义,此类策略匹配所有名称。

为确保它不会影响其他策略,全覆盖策略使用负优先级。

虽然此类全覆盖队列可以使用 rabbitmqctl 以及模式 .* 和负优先级来声明,但 rabbitmqadmin v2 提供了一个专用命令来声明此类专用策略

# This queue will match all objects in the vh.1 virtual host, that are not matched by another policy.
# To that end, it uses a negative priority and '.*' for the pattern.
rabbitmqadmin --vhost 'vh.1' policies declare_blanket \
--name 'blanket.queues' \
--apply-to 'queues' \
--definition '{"federation-upstream-set": "all"}'

全覆盖策略通常是临时的,用于特定目的,例如在从一个集群到另一个集群的 蓝绿部署式 迁移期间启用 队列联合

更新策略

可以通过使用不同的定义、优先级等重新声明来更新策略。这要求操作员拥有完整的策略定义。

或者,rabbitmqadmin v2 提供了可以修改策略定义、声明覆盖策略和全覆盖策略的命令。

策略重定义

如果已知完整的策略定义,重定义 具有更新定义和(可选)新优先级但名称相同的策略将对其进行更新。

重要

新设置对队列、流和交换机的影响需要片刻时间才能生效,对于拥有大量实体(例如数千个)的集群尤其如此。

删除策略定义键

要从策略定义中删除一个或多个键,请使用 rabbitmqadmin policies delete_definition_keys

# removes all keys related to classic queue mirroring (that feature was removed in RabbitMQ 4.x)
# from the definition of a policy named "cq.policies.1" in virtual host vh-1
rabbitmqadmin --vhost "vh-1" policies delete_definition_keys --name "cq.policies.1" --definition-keys "ha-mode,ha-params,ha-promote-on-shutdown,ha-promote-on-failure,ha-sync-mode,ha-sync-batch-size"

--definitions-keys 参数接受单个定义键或以逗号分隔的键列表。

要在虚拟主机中的所有策略上执行相同的操作,请使用 rabbitmqadmin policies delete_definition_keys_from_all_in

# removes all keys related to classic queue mirroring (that feature was removed in RabbitMQ 4.x)
# from all policy definitions in virtual host vh-1
rabbitmqadmin --vhost "vh-1" policies delete_definition_keys_from_all_in --definition-keys "ha-mode,ha-params,ha-promote-on-shutdown,ha-promote-on-failure,ha-sync-mode,ha-sync-batch-size"

部分更新策略定义

rabbitmqadmin policies patch 是一个可以使用部分定义更新策略的命令,例如,向现有策略添加 max-length

rabbitmqadmin policies patch \
--name "cq.pol.1" \
--definition '{"max-length": 1000000}'

新的 --definition 对象将被合并到现有的策略定义中。

在以下示例中,默认虚拟主机 (/) 中名为 queues.pol.1 的现有策略被更新,以为匹配的队列启用 队列联合 到所有配置的上游,而不影响其余的策略定义

rabbitmqadmin policies patch \
--name "queues.pol.1" \
--definition '{"federation-upstream-set":"all"}'

运营商策略

与常规策略的区别

有时操作员有必要强制执行某些策略。例如,可能需要强制执行 队列 TTL,但仍然允许其他用户管理策略。操作员策略允许这样做。

操作员策略非常类似于常规策略,但它们的定义使用方式不同。在将结果应用于匹配的队列之前,它们会与常规策略定义进行合并。

因为操作员策略可能会意外更改队列属性,进而更改应用程序的假设和语义,所以它们仅限于少数几个参数

经典QuorumStream
delivery-limit
expires
max-in-memory-bytes
max-in-memory-length
max-length
max-length-bytes
message-ttl
overflow
queue-version
target-group-size

与常规策略的冲突解决

操作员策略和常规策略在其定义中可以包含相同的键。当这种情况发生时,将选择更保守的值作为有效值。例如,如果匹配的操作员策略定义将 max-length 设置为 50,而匹配的常规策略定义使用值 100,则使用值 50。然而,如果常规策略的值为 20,则会使用 20。因此,操作员策略不仅仅是覆盖常规策略值。它们强制执行限制,但尽可能不覆盖用户提供的策略。

经典QuorumStream
delivery-limit
  • 更小的值
expires
  • 更小的值
  • 两个策略中较小的值
  • 策略优于队列参数
max-in-memory-bytes
  • 更小的值
max-in-memory-length
  • 更小的值
max-length
  • 更小的值
  • 更小的值
max-length-bytes
  • 更小的值
  • 更小的值
  • 两个策略中较小的值
  • 策略优于队列参数
message-ttl
  • 更小的值
  • 更小的值
overflow
  • 操作员策略值
  • 操作员策略值
queue-version
  • 操作员策略值
target-group-size
  • 更大的值

客户端提供的 x-arguments 和用户策略都提供相同的键时,前者优先。此规则的例外是所有流配置设置以及仲裁队列的 (x-)overflow,此时策略优先。

但是,如果也使用了操作员策略,它也将优先于客户端提供的参数。操作员策略是一种保护机制,会覆盖客户端提供的值和用户策略值。

使用操作员策略为与资源使用相关的应用程序控制参数(例如,磁盘空间峰值使用量)引入护栏。

定义操作员策略

操作员策略的定义方式与常规(用户)策略非常相似。当使用 rabbitmqctl 时,命令名称为 set_operator_policy 而不是 set_policy。在 HTTP API 中,请求路径中的 /api/policies/ 变为 /api/operator-policies/

rabbitmqctl set_operator_policy transient-queue-ttl \
"^amq\." '{"expires":1800000}' \
--priority 1 \
--apply-to queues
危险

当多个策略匹配一个实体且它们的优先级相等时,生效的策略将不确定地选择。应注意各种策略使用的优先级,以避免此类情况发生

如何禁用操作员策略更改

可以通过配置禁用通过 HTTP API 和 Web UI 修改操作员策略。这使得操作员策略对于所有用户而言,通过 HTTP API 和 Web UI 变为只读。

management.restrictions.operator_policy_changes.disabled = true

为新虚拟主机预配置默认操作员策略

操作员策略可以在 rabbitmq.conf 中为名称匹配模式的虚拟主机组进行预配置。当虚拟主机被动态(例如按需)创建但必须具有一致的 护栏 (guardrails) 时,这非常有用。

## When a new virtual host with a name matching ^prod-.* is created,
## an operator policy named 'limits` will be added to it automatically.

## In this example, "limits" is the operator policy name.
default_policies.operator.limits.vhost_pattern = ^prod-.*
default_policies.operator.limits.queue_pattern = .*
default_policies.operator.limits.apply_to = queues
default_policies.operator.limits.max_length = 10000
default_policies.operator.limits.message_ttl = 86400000

更新操作员策略

提示

操作员策略可以通过多种方式修改,与 常规策略 非常相似。

操作员策略可以通过使用不同的定义、优先级等重新声明来更新。这要求操作员拥有完整的策略定义。

或者,rabbitmqadmin v2 提供了可以修改操作员策略定义的命令。

操作员策略重定义

如果已知完整的策略定义,重定义 具有更新定义和(可选)新优先级但名称相同的策略将对其进行更新。

重要

新设置对队列、流和交换机的影响需要片刻时间才能生效,对于拥有大量实体(例如数千个)的集群尤其如此。

删除操作员策略定义键

要从策略定义中删除一个或多个键,请使用 rabbitmqadmin policies delete_definition_keys

# removes all keys related to classic queue mirroring (that feature was removed in RabbitMQ 4.x)
# from the definition of an operator policy named "cq.policies.1" in virtual host vh-1
rabbitmqadmin --vhost "vh-1" operator_policies delete_definition_keys \
--name "cq.op-policies.1" \
--definition-keys "ha-mode,ha-params,ha-promote-on-shutdown,ha-promote-on-failure,ha-sync-mode,ha-sync-batch-size"

--definitions-keys 参数接受单个定义键或以逗号分隔的键列表。

要在虚拟主机中的所有策略上执行相同的操作,请使用 rabbitmqadmin operator_policies delete_definition_keys_from_all_in

# removes all keys related to classic queue mirroring (that feature was removed in RabbitMQ 4.x)
# from all operator policy definitions in virtual host vh-1
rabbitmqadmin --vhost "vh-1" operator_policies delete_definition_keys_from_all_in --definition-keys "ha-mode,ha-params,ha-promote-on-shutdown,ha-promote-on-failure,ha-sync-mode,ha-sync-batch-size"

部分更新操作员策略定义

rabbitmqadmin operator_policies patch 是一个可以使用部分定义更新策略的命令,例如,向现有策略添加 max-length

rabbitmqadmin operator_policies patch --name "cq.op-pol.1" --definition '{"max-length": 1000000}'

新的 --definition 对象将被合并到现有的策略定义中。

在以下示例中,默认虚拟主机 (/) 中名为 queues.op-pol.1 的现有操作员策略被更新,以在所有匹配的队列上设置 message-ttl,而不影响其余的策略定义

rabbitmqadmin operator_policies patch --name "queues.op-pol.1" --definition '{"message-ttl": 3600000}'

删除操作员策略

可以使用 rabbitmqctl clear_operator_policyrabbitmqadmin operator_policies delete 删除操作员策略。

rabbitmqctl clear_operator_policy --vhost "vh.1" "policy.name"

故障排除

多个策略具有冲突的优先级

rabbitmqadmin v2 可以列出特定虚拟主机或所有虚拟主机中具有冲突优先级的策略

# lists policies with conflicting priorities in a specific virtual host
rabbitmqadmin --vhost "target.vhost" policies list_conflicting_in
# lists policies with conflicting priorities across all virtual hosts
rabbitmqadmin policies list_conflicting

或者,列出虚拟主机中的所有策略并手动查找相等的优先级

rabbitmqctl --vhost "target.vhost" list_policies --formatter=pretty_table

要缩小影响特定对象的策略范围,请使用 list_matching_object

rabbitmqadmin --vhost "target.vhost" policies list_matching_object \
--name "a.queue" \
--type "queues"

查找任何和所有具有相等优先级的策略。其中只有一个将应用于匹配的对象(队列、流、交换机),并且该选择应被视为非确定性的(随机的)。

策略模式或目标类型与对象的名称或类型不匹配

要验证此假设,请使用 rabbitmqadmin v2 列出匹配相关对象(例如队列)的策略。

# lists all policies that match a queue named "a.queue" in a virtual host named "target.vhost"
rabbitmqadmin --vhost "target.vhost" policies list_matching_object \
--name "a.queue" \
--type "queues"

如果结果为空,则意味着目标虚拟主机中没有策略与目标对象(队列、流、交换机)匹配。

在错误的虚拟主机中声明了策略

策略以虚拟主机为作用域,即属于特定的虚拟主机,仅应用于该虚拟主机中的对象(队列、流、交换机)。

策略可能被错误地声明在默认虚拟主机中。要验证此假设,仅列出该虚拟主机中的策略。

rabbitmqctl --vhost "target.vhost" list_policies --formatter=pretty_table

如果结果为空,则意味着目标虚拟主机中没有定义任何策略。

© . This site is unofficial and not affiliated with VMware.