跳至主内容
版本:4.2

策略

概述

尽管 RabbitMQ 的大部分配置都位于配置文件中,但有些事物与使用配置文件并不兼容。

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

RabbitMQ 中的此类值存储为运行时参数。策略就是运行时参数使用方式的一个例子。

本指南重点介绍策略和运算符策略。

策略为何存在

提示

策略是一种声明式机制,用于配置队列、流、交换机的特定属性。它们旨在处理可能在运行时更改的参数。

注意

由于队列(流)类型在声明时设置且无法更改,因此根据设计,策略无法用于配置队列类型。要指定队列(流)类型,请使用可选参数

策略是一种声明式的、虚拟主机范围内的机制,用于动态地重新配置队列、交换机、流和某些插件(特别是联盟)的可选参数

策略与应用程序设置的可选参数

在解释策略是什么以及如何使用它们之前,有必要解释一下它们为何被引入 RabbitMQ。

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

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

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

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

在较新版本的 RabbitMQ 中,可以通过策略控制的功能集与客户端提供的参数控制的功能集不同。

策略如何工作

关键策略属性是:

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

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

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

策略可以随时更改。当策略定义更新时,其对匹配的交换机和队列的影响将重新应用。通常会立即发生,但对于非常繁忙的队列可能需要一些时间(例如几秒钟)。

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

策略可用于配置:

以及其他功能。

不能使用策略设置的内容

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

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

如何定义策略

定义策略的示例如下:

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

当多个策略匹配实体且它们具有相同的优先级时,将以不确定的方式选择生效的策略。应避免这种情况,注意各种策略使用的优先级。

这会将值 "all" 与键 "federation-upstream-set" 匹配,应用于虚拟主机 "/" 中所有以 "federated." 开头的交换机。

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

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

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

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

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

策略优先级

策略模式会与交换机和队列名称进行匹配,以确定哪个策略(如果有)会将一组键值对(该策略的定义)注入到匹配队列(交换机)的可选参数中。

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

重要

每个队列或交换机最多匹配一个策略。然后根据优先级对匹配的策略进行排序,优先级最高的策略将生效。

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

危险

当多个策略匹配实体且它们具有相同的优先级时,将以不确定的方式选择生效的策略。应避免这种情况,注意各种策略使用的优先级。

然后根据优先级对匹配的策略进行排序,优先级最高的策略将生效。

当多个策略匹配实体且它们具有相同的优先级时,将以不确定的方式选择生效的策略。应避免这种情况,注意各种策略使用的优先级。

组合策略定义

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

提示

另请参阅下面的更新策略

联盟策略定义需要指定一个上游集,因此我们的定义中需要 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'

声明全局策略

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

为确保其不影响其他策略,全局策略使用负优先级。

虽然可以使用模式为 .* 和负优先级的 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,同时仍允许其他用户管理策略。运算符策略允许这样做。

运算符策略与普通策略非常相似,但它们的定义使用方式不同。它们与普通策略定义合并,然后将结果应用于匹配的队列。

由于运算符策略可能会意外更改队列属性,进而改变应用程序的假设和语义,因此它们仅限于少数参数:

经典仲裁
delivery-limit
expires
max-in-memory-bytes
max-in-memory-length
max-length
max-length-bytes
message-ttl
target-group-size

与普通策略的冲突解决

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

经典仲裁
delivery-limit
  • 较小的值
expires
  • 较小的值
  • 两个策略中较小的值
  • 策略优先于队列参数
max-in-memory-bytes
  • 较小的值
max-in-memory-length
  • 较小的值
max-length
  • 较小的值
  • 较小的值
max-length-bytes
  • 较小的值
  • 较小的值
  • 两个策略中较小的值
  • 策略优先于队列参数
message-ttl
  • 较小的值
  • 较小的值
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 中为名称与模式匹配的虚拟主机组预先配置运算符策略。当动态创建(例如按需)虚拟主机但必须具有一致的保护措施时,这很有用。

## 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.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 的现有运算符策略将被更新,以便为匹配队列启用队列联盟到所有已配置的上游,而不会影响其他策略定义。

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

删除运算符策略

可以使用 rabbitmqctl clear_operator_policyrabbitmqadmin operator_policies delete 删除运算符策略。

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

故障排除

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

要验证此假设,请列出虚拟主机中的策略,看看是否有任何策略的优先级与您正在排查的策略相同。

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

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

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"

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

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

要验证此假设,请使用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.