跳至主内容
版本:4.2

虚拟主机

简介

RabbitMQ 是一个多租户系统:连接、交换器、队列、绑定、用户权限、策略以及其他一些实体都属于虚拟主机,即逻辑实体分组。如果您熟悉 Apache 中的虚拟主机Nginx 中的服务器块,那么这个概念是相似的。

不过,有一个重要的区别:Apache 中的虚拟主机是在配置文件中定义的;而 RabbitMQ 中的虚拟主机不是这样:虚拟主机是使用 rabbitmqctl 或 HTTP API 创建删除的。

逻辑与物理分离

虚拟主机提供资源的逻辑分组和分离。物理资源的分离并不是虚拟主机的目标,尽管 某些资源可以为单个虚拟主机设置限制

例如,RabbitMQ 中的 资源权限 是按虚拟主机作用域划分的。用户没有全局权限,只有在一个或多个虚拟主机中的权限。用户标签可以被视为全局权限,但它们是规则的例外。

因此,在谈论用户权限时,非常重要的一点是要明确它们适用于哪个(哪些)虚拟主机。

虚拟主机与客户端连接

虚拟主机有一个名称。当 AMQP 0-9-1 客户端连接到 RabbitMQ 时,它会指定一个 vhost 名称进行连接。如果身份验证成功,并且提供的用户名 获得了 该虚拟主机的权限,则连接将建立。

到某个虚拟主机的连接只能在该虚拟主机中操作交换器、队列、绑定等。例如,不同虚拟主机中的队列和交换器之间的“互连”只有在应用程序同时连接到两个虚拟主机时才可能。例如,应用程序可以从一个虚拟主机消费,然后重新发布到另一个。这种情况可能涉及不同集群或同一集群(或单个节点)中的虚拟主机。RabbitMQ Shovel 插件 就是这类应用程序的一个示例。

创建虚拟主机

可以使用 CLI 工具或 HTTP API 端点创建虚拟主机。

新创建的虚拟主机将包含一组默认的 交换器,但没有其他实体,也没有 用户权限。要使某个用户能够连接和使用虚拟主机,必须 授予 将使用该虚拟主机的每个用户的权限,例如使用 rabbitmqctl set_permissions

使用 CLI 工具

可以使用 rabbitmqctladd_vhost 命令创建虚拟主机,该命令接受虚拟主机名称作为唯一必需的参数。

rabbitmqctl add_vhost qa1

使用 HTTP API

可以使用 PUT /api/vhosts/{name} HTTP API 端点创建虚拟主机,其中 {name} 是虚拟主机的名称。

这是一个使用 curl 通过联系 rabbitmq.local:15672 节点来创建名为 vh1 的虚拟主机的示例

curl -u userename:pa$sw0rD -X PUT http://rabbitmq.local:15672/api/vhosts/vh1

批量创建和预置

虚拟主机的创建涉及一个全局的阻塞事务。每个节点都需要执行一系列设置步骤,这些步骤的开销相当大。实际上,虚拟主机的创建可能需要几秒钟。

当在一个循环中创建多个虚拟主机时,CLI 和 HTTP API 客户端可能会超出实际的虚拟主机创建速率而遇到超时。如果发生这种情况,应增加操作超时时间并在操作之间引入延迟。

定义导出和导入是部署时预配置多个虚拟主机的推荐方法。

虚拟主机元数据

虚拟主机可以关联元数据

  • 描述
  • 一组标签
  • 为虚拟主机配置的默认队列类型

所有这些设置都是可选的。它们可以在虚拟主机创建时提供,也可以稍后更新。

使用 CLI 工具

虚拟主机元数据可以在创建时设置,也可以稍后更新。

# Create a virtual host with metadata
rabbitmqctl add_vhost qa1 --description "QA env 1" --default-queue-type quorum

# Update virtual host metadata

rabbitmqctl update_vhost_metadata qa1 --description "QA environment for issue 1662" --default-queue-type quorum --tags qa,project-a,qa-1662

# List virtual hosts with metadata

rabbitmqctl -q --formatter=pretty_table list_vhosts name description tags default_queue_type

使用 HTTP API

PUT /api/vhosts/{name} HTTP API 端点接受一些可选的键。

这是一个使用 curl 通过联系 rabbitmq.local:15672 节点创建名为 qa1 的虚拟主机的示例。将使用 Quorum 队列 作为默认队列类型,并添加描述和两个标签。

curl -u userename:pa$sw0rD -X PUT http://rabbitmq.local:15672/api/vhosts/qa1 \
-H "content-type: application/json" \
--data-raw '{"description": "QA environment 1", "tags": "qa,project-a", "default_queue_type": "quorum"}'

可以使用相同的端点来更新上述所有或部分元数据值。

curl -u userename:pa$sw0rD -X PUT http://rabbitmq.local:15672/api/vhosts/qa1 \
-H "content-type: application/json" \
--data-raw '{"description": "QA environment for issue 1662", "tags": "qa,project-a,qa-1662", "default_queue_type": "quorum"}'

GET /api/vhosts/{name} 端点返回虚拟主机元数据。

curl -u userename:pa$sw0rD -X GET http://rabbitmq.local:15672/api/vhosts/qa1

默认队列类型 (DQT)

当客户端声明一个队列而未显式指定其类型(使用 x-queue-type 头)时,将使用可配置的默认类型。可以通过在虚拟主机元数据中指定(如上所述)来覆盖此默认值。

rabbitmqctl add_vhost qa1 --description "QA environment 1" --default-queue-type quorum --tags qa,project-a

支持的队列类型为

  • "quorum"
  • "stream"
  • "classic"

默认值仅对新队列声明有效;更新默认值不会影响任何现有队列或流的队列类型,因为队列类型是不可变的,一旦声明就无法更改。

对于未显式设置队列类型的声明队列,有效的虚拟主机默认值将在 定义导出时 注入到队列属性中。

节点范围的默认队列类型 (Node-wide DQT)

而不是为集群中的每个虚拟主机配置相同的默认队列类型,可以使用 rabbitmq.conf 设置节点范围的默认值。

# supported values are: quorum, stream, classic, or a custom queue type module name
default_queue_type = quorum

当同时设置了虚拟主机 DQT 和节点范围 DQT 时,虚拟主机 DQT 将优先。

迁移到 Quorum 队列:一种放宽队列属性等价性检查的方法

可以使用布尔设置 quorum_queue.property_equivalence.relaxed_checks_on_redeclaration 来放宽队列类型的 队列属性等价性检查,该设置使得可以放宽 Quorum 队列的队列属性等价性检查。

具体来说,当重新声明一个 Quorum 队列并且客户端提供的类型设置为“classic”时,此设置将有助于避免通道异常,从而更容易逐步迁移到 Quorum 队列,而无需在短时间内升级所有应用程序。

# this setting is meant to be used during transitionary periods when
# RabbitMQ default queue type is changed but not all applications have been
# updated yet
quorum_queue.property_equivalence.relaxed_checks_on_redeclaration = true

删除虚拟主机

可以使用 CLI 工具或 HTTP API 端点删除虚拟主机。

删除虚拟主机将永久删除其中的所有实体(队列、交换器、绑定、策略、权限等)。

使用 CLI 工具

可以使用 rabbitmqctldelete_vhost 命令删除虚拟主机,该命令接受虚拟主机名称作为唯一必需的参数。

rabbitmqctl delete_vhost qa1

使用 HTTP API

可以使用 DELETE /api/vhosts/{name} HTTP API 端点删除虚拟主机,其中 {name} 是虚拟主机的名称。

这是一个使用 curl 通过联系 rabbitmq.local:15672 节点来删除名为 vh1 的虚拟主机的示例

curl -u userename:pa$sw0rD -X DELETE http://rabbitmq.local:15672/api/vhosts/vh1

删除多个虚拟主机

rabbitmqadmin 支持使用名称匹配模式一次删除多个虚拟主机。

危险

这是一个极其危险的操作,必须非常小心使用。

此命令将删除所有匹配所提供正则表达式模式的虚拟主机。这些虚拟主机中的所有数据将永久丢失,包括

  • 队列、流和分区流
  • 交换器和绑定
  • 消息
  • 用户权限
  • Federation 上游和链接
  • Shovels
  • 策略和操作者策略
  • 运行时参数

始终先使用 --dry-run 验证将要删除的内容,然后再执行实际删除。

# ALWAYS run with --dry-run first to see what would be deleted
rabbitmqadmin vhosts delete_multiple --name-pattern "^test-.*" --dry-run

# After verifying with --dry-run, use --approve to perform the actual deletion

# This will delete ALL virtual hosts whose names start with "test-"

rabbitmqadmin vhosts delete_multiple --name-pattern "^test-.\*" --approve

注意

默认虚拟主机 (/) 始终保留,并且永远不会被此命令删除,即使它匹配模式。

删除保护

虚拟主机可以被保护以免被删除。受保护的虚拟主机在删除保护被移除之前无法被删除。

使用 CLI 工具

可以使用 rabbitmqctlrabbitmqadmin 来保护虚拟主机免于删除。

rabbitmqctl enable_vhost_protection_from_deletion "vhost-name"

此时,尝试删除虚拟主机将失败并显示特定消息。

rabbitmqctl delete_vhost "vhost-name"
# ...
# => Error:
# => Cannot delete this virtual host: it is protected from deletion. To lift the protection, inspect and update its metadata

要移除保护

rabbitmqctl disable_vhost_protection_from_deletion "vhost-name"

在移除保护后,可以再次删除虚拟主机。

rabbitmqctl delete_vhost "vhost-name"
# => Deleting vhost "vhost-name" ...

要查看虚拟主机是否受保护免于删除,请使用 list_vhosts 命令并添加一个额外的列,protected_from_deletion

rabbitmqctl list_vhosts name tags default_queue_type metadata protected_from_deletion --formatter=pretty_table
# => Listing vhosts ...
# => ┌───────────────────────────┬─────────────────────────┐
# => │ name │ protected_from_deletion │
# => ├───────────────────────────┼─────────────────────────┤
# => │ / │ false │
# => ├───────────────────────────┼─────────────────────────┤
# => │ vh1 │ true │
# => ├───────────────────────────┼─────────────────────────┤
# => │ vh2 │ false │
# => └───────────────────────────┴─────────────────────────┘

使用 HTTP API

可以使用 POST /api/vhosts/{name}/deletion/protection HTTP API 端点来保护虚拟主机免于删除,其中 {name} 是虚拟主机的名称。

这是一个使用 curl 通过联系 rabbitmq.local:15672 节点来保护名为 vh1 的虚拟主机免于删除的示例。

curl -u userename:pa$sw0rD -X POST http://rabbitmq.local:15672/api/vhosts/vh1/deletion/protection

此时,尝试删除虚拟主机将失败,并返回 412 Precondition Failed 状态。

curl -sL -u guest:guest -X DELETE https://:15672/api/vhosts/vh1/
# => < HTTP/1.1 412 Precondition Failed

响应体将包含一个特定的错误,与 CLI 工具的输出类似。

{
"error": "precondition_failed",
"reason": "Refusing to delete virtual host 'vh1' because it is protected from deletion"
}

要移除保护,请使用 DELETE /api/vhosts/{name}/deletion/protection

curl -u userename:pa$sw0rD -X DELETE http://rabbitmq.local:15672/api/vhosts/vh1/deletion/protection

在移除保护后,可以再次删除虚拟主机。

curl -vv -sL -u guest:guest -X DELETE https://:15672/api/vhosts/
# ...
# => < HTTP/1.1 204 No Content

要查看虚拟主机是否受保护免于删除,请使用 GET /api/vhostsGET /api/vhosts/{vhost} 端点,然后检查 metadata.protected_from_deletion 响应体字段。

curl -sL -u guest:guest -X GET https://:15672/api/vhosts/vh1
# => {
# => "name": "vh1",
# => "description": "",
# => "tags": [],
# => "default_queue_type": "classic",
# => "protected_from_deletion": true,
# => "metadata": {
# => "description": "",
# => "tags": [],
# => "default_queue_type": "classic",
# => "protected_from_deletion": true
# => },
# => "tracing": false,
# => "cluster_state": {
# => "rabbit@sunnyside": "running"
# => }
# => }

定义导入

如果虚拟主机是通过 定义文件 创建的,添加一个新的元数据键 "protected_from_deletion" 并将其设置为 true,将在创建时将虚拟主机标记为受保护。

{
"name": "protected",
"description": "",
"metadata": {
"description": "This virtual host is protected from deletion with a special metadata key",
"tags": [],
"default_queue_type": "classic",
"protected_from_deletion": true
},
"tags": [],
"default_queue_type": "classic"
}

限制

在某些情况下,限制 vhost 中允许的最大队列数量或并发客户端连接数是可取的。每虚拟主机的限制正是为这些情况而设计的。

这些限制可以使用 rabbitmqctlHTTP API 进行配置。

配置限制

虚拟主机限制可以使用 rabbitmqctlrabbitmqadmin 进行配置。

配置最大连接限制

要限制虚拟主机 vhost_name 中的并发客户端连接总数,请使用以下限制定义:

rabbitmqctl set_vhost_limits -p vhost_name '{"max-connections": 256}'

要阻止客户端连接到 vhost,请将限制设置为零。

rabbitmqctl set_vhost_limits -p vhost_name '{"max-connections": 0}'

配置最大队列数

要限制虚拟主机 vhost_name 中的队列总数,请使用以下限制定义:

rabbitmqctl set_vhost_limits -p vhost_name '{"max-queues": 1024}'

列出虚拟主机限制

要列出虚拟主机的限制:

# uses the default virtual host (/)
rabbitmqctl list_vhost_limits

# or for a specific virtual host

rabbitmqctl list_vhost_limits -p vhost_name

清除虚拟主机限制

要清除虚拟主机限制:

rabbitmqctl clear_vhost_limits -p vhost_name '{"max-connections": 256}'

预配置虚拟主机限制

虚拟主机限制可以在 rabbitmq.conf 中为虚拟主机组进行预配置。这在虚拟主机由集群用户动态创建时很有用(例如,RabbitMQ 集群被作为一种服务提供),但所有新创建的虚拟主机都必须使用一组一致的限制。

可以定义多个限制集,每个限制集都有一个匹配虚拟主机名称的模式和要设置的限制集。

# Default limits for virtual hosts starting with "pipelines"
default_limits.vhosts.1.pattern = ^pipelines
default_limits.vhosts.1.max_connections = 10
default_limits.vhosts.1.max_queues = 1000

# Default limits for virtual hosts starting with "telemetry"
default_limits.vhosts.2.pattern = ^telemetry
default_limits.vhosts.2.max_connections = 10000
default_limits.vhosts.2.max_queues = 10000

# Default limits for all other virtual hosts
default_limits.vhosts.3.pattern = .*
default_limits.vhosts.3.max_connections = 20
default_limits.vhosts.3.max_queues = 20

使用 -1 表示特定限制不设限。

虚拟主机与 STOMP

与 AMQP 0-9-1 一样,STOMP 也包含了 虚拟主机概念。详情请参阅 STOMP 指南

虚拟主机与 MQTT

与 AMQP 0-9-1 和 STOMP 不同,MQTT 没有虚拟主机的概念。MQTT 连接默认使用单个 RabbitMQ 主机。有一些 MQTT 特定的约定和功能,使得客户端无需对客户端库进行任何修改即可连接到特定的 vhost。详情请参阅 MQTT 指南

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