Rabbit 集群指南

本博客围绕RabbitMQ集群展开,介绍了集群构建方法与要求,如通过配置文件、DNS等方式搭建,需确保主机名可解析、端口可访问。还阐述了节点复制、身份验证、故障处理等内容,以及升级、单机集群搭建等操作,同时提及RAM节点特性与创建更改方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本指南涵盖与RabbitMQ群集相关的基本主题:

更多。群集构建和对等发现是一个密切相关的主题,对等发现和群集构建都侧重于自动化相关主题。有关队列内容(消息)复制,请参阅“镜像队列”指南。

 

A RabbitMQ broker 是一个逻辑分组,这个逻辑分组包含一个或多个Erlang节点,每个节点运行RabbitMQ应用程序并共享用户,虚拟主机,队列,交换,绑定和运行时参数。有时我们将节点集合称为集群。

群集构建

构建集群的方法

A RabbitMQ 集群 可以按照下列方式搭建:

  • 通过在配置文件中列出群集节点来声明
  • 声明性地使用基于DNS的发现
  • 声明性地使用AWS(EC2)实例发现(通过插件)
  • 声明性地使用Kubernetes发现(通过插件)
  • 声明性地使用基于Consul的发现(通过插件)
  • 声明性地使用基于etcd的发现(通过插件)
  • 用rabbitmqctl手动

有关详细信息,请参阅群集形成指南。

可以动态更改群集的组成。所有RabbitMQ服务都开始在单个节点上运行。这些节点可以连接成集群,然后再次转回单个代理。

群集构建要求

RabbitMQ 节点使用域名(短期或完全限定(FQDN))相互寻址。因此,所有集群成员的主机名必须可以从所有集群节点以及可能使用诸如rabbitmqctl之类的命令行工具的计算机上解析。

主机名解析可以使用任何标准的OS提供的方法:

  • DNS记录
  • 本地 host files (e.g. /etc/hosts)

在限制性更强的环境中,DNS记录或主机文件修改受到限制,不可能或不受欢迎,可以将Erlang VM配置为使用备用主机名解析方法,例如备用DNS服务器,本地文件,非标准主机文件位置,或混合方法。这些方法可以与标准OS主机名解析方法协同工作。

要使用FQDN,请参阅配置指南中的RABBITMQ_USE_LONGNAME。

 

RabbitMQ 节点绑定到端口(打开服务器TCP套接字)以接受客户端和CLI工具连接。其他进程和工具(如SELinux)可能会阻止RabbitMQ绑定到端口。发生这种情况时,节点将无法启动。CLI工具,客户端库和RabbitMQ节点也打开连接(客户端TCP套接字)。防火墙可以阻止节点和CLI工具相互通信。确保可以访问以下端口:

  • 4369: epmd,RabbitMQ节点和CLI工具使用的对等发现服务
  • 5672, 5671: 由AMQP 0-9-1和1.0客户端使用,没有和使用TLS
  • 25672: 用于节点间和CLI工具通信(Erlang分发服务器端口)并从动态范围分配(默认情况下限于单个端口,计算为AMQP端口+ 20000)。除非确实需要这些端口上的外部连接(例如,群集使用federation或在子网外的计算机上使用CLI工具),否则不应公开这些端口。有关详情,请参阅网络指南
  • 35672-35682: CLI工具(Erlang分发客户端端口)用于与节点通信,并从动态范围(计算为服务器分发端口+ 10000到服务器分发端口+ 10010)分配。有关详情,请参阅网络指南
  • 15672: HTTP API客户端,管理UI和rabbitmqadmin(仅当启用了管理插件时)
  • 61613, 61614: 没有和使用TLS的STOMP客户端(仅当启用了STOMP插件时)
  • 1883, 8883: (如果启用了MQTT插件),则没有和使用TLS的MQTT客户端
  • 15674: STOMP-over-WebSockets客户端(仅当启用了Web STOMP插件时)
  • 15675: MQTT-over-WebSockets客户端(仅当启用了Web MQTT插件时)

可以将RabbitMQ配置为使用不同的端口和特定的网络接口。

 

群集中的节点

什么是复制?

RabbitMQ代理操作所需的所有数据/状态都将在所有节点之间复制。一个例外是消息队列,它们默认驻留在一个节点上,尽管它们是可见的并且可以从所有节点访问。要跨群集中的节点复制队列,请参阅有关高可用性的文档(注意:本指南是镜像的先决条件)。

节点是Equal Peers

一些分布式系统具有领导者和跟随者节点,而这些在RabbitMQ通常不适用。RabbitMQ集群中的所有节点都是相等的对等体:RabbitMQ核心中没有特殊节点。当考虑队列镜像和插件时,该主题变得更加细微,但是对于大多数意图和目的,所有集群节点都应该被认为是相同的

可以对任何节点执行许多CLI工具操作。HTTP API客户端可以定位任何群集节点。

各个插件可以指定(选择)某些节点在一段时间内“特殊”。例如,federation links 位于特定群集节点上。如果该节点发生故障,链接将在另一个节点上重新启动。

在早于3.6.7的版本中,RabbitMQ管理插件使用专用节点进行统计信息收集和聚合。

CLI工具如何向节点(以及彼此之间的节点)进行身份验证:Erlang Cookie

RabbitMQ节点和CLI工具(例如rabbitmqctl)使用cookie来确定是否允许它们彼此通信。要使两个节点能够通信,它们必须具有相同的共享密钥,称为Erlang cookie。cookie只是一串字母数字字符,最大为255个字符。它通常存储在本地文件中。该文件必须只能由所有者访问(例如,具有600或类似的UNIX权限)。每个群集节点必须具有相同的cookie。

如果该文件不存在,Erlang VM将尝试在RabbitMQ服务器启动时创建一个随机生成的值。使用此类生成的cookie文件仅适用于开发环境。由于每个节点将独立生成自己的值,因此该策略在群集环境中不可行。 Erlang cookie生成应该在集群部署阶段完成,理想情况下使用自动化和编排工具,如Chef,Puppet,BOSH,Docker或类似工具。

在UNIX系统上,cookie通常位于/var/lib/rabbitmq/.erlang.cookie(由服务器使用)和$ HOME / .erlang.cookie(由CLI工具使用)中。请注意,由于`$ HOME`的值因用户而异,因此需要为将使用CLI工具的每个用户放置cookie文件的副本。这适用于非特权用户和`root`。

在Windows上,cookie文件位置因使用的Erlang版本以及是否设置了HOMEDRIVE或HOMEPATH环境变量而异。

对于以20.2开头的Erlang版本,cookie文件位置为:

  • %HOMEDRIVE%%HOMEPATH%\.erlang.cookie (通常为用户%USERNAME% 的 C:\Users\%USERNAME%\.erlang.cookie) 如果同时设置了HOMEDRIVE和HOMEPATH环境变量
  • %USERPROFILE%\.erlang.cookie (通常为C:\Users\%USERNAME%\.erlang.cookie)如果HOMEDRIVE和HOMEPATH都没有设定
  • 对于RabbitMQ Windows服务 - %USERPROFILE%\.erlang.cookie (通常为 C:\WINDOWS\system32\config\systemprofile)

必须同步Windows服务帐户和运行CLI工具的用户使用的cookie文件。

对应Erlang versions 早期版本 (例如 19.3 or 20.1), cookie文件位置为

  • %HOMEDRIVE%%HOMEPATH%\.erlang.cookie (通常为用户%USERNAME% 的 C:\Users\%USERNAME%\.erlang.cookie )如果同时设置了HOMEDRIVE和HOMEPATH环境变量
  • %USERPROFILE%\.erlang.cookie (通常为 C:\Users\%USERNAME%\.erlang.cookie) 如果HOMEDRIVE和HOMEPATH都没有设定
  • 对于RabbitMQ Windows服务 - %WINDIR%\.erlang.cookie (通常为C:\Windows\.erlang.cookie)

必须同步Windows服务帐户和运行CLI工具的用户使用的cookie文件。

或者,您可以在RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS环境变量值中添加选项“-setcookie value”:

RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-setcookie cookie-value"

这是最不安全的选项,通常不推荐。

当cookie配置错误(例如,不相同)时,RabbitMQ将记录错误,例如“Connection attempt from disallowed node”和“Could not auto-cluster”。当类似rabbitmqctl之类的CLI工具无法使用RabbitMQ进行身份验证时,消息通常会显示

* epmd reports node 'rabbit' running on port 25672
* TCP connection succeeded but Erlang distribution failed
* suggestion: hostname mismatch?
* suggestion: is the cookie set correctly?
* suggestion: is the Erlang distribution using TLS?

错误放置的cookie文件或cookie值不匹配是此类故障的最常见情况。当使用最近的Erlang / OTP版本时,身份验证失败包含更多信息,并且可以更好地识别cookie不匹配:

* connected to epmd (port 4369) on warp10
* epmd reports node 'rabbit' running on port 25672
* TCP connection succeeded but Erlang distribution failed

* Authentication failed (rejected by the remote node), please check the Erlang cookie
有关更多信息,请参阅CLI工具指南。

群集和客户端

假设所有集群成员都可用,客户端可以连接到任何节点并执行任何操作。节点将客户端操作透明地路由到队列主节点。

使用所有支持的消息传递协议,客户端一次只能连接到一个节点。

如果节点发生故障,客户端应该能够重新连接到其他节点,恢复其拓扑并继续操作。因此,大多数客户端库都接受端点列表(主机名或IP地址)作为连接选项。如果客户端支持,则在初始连接和连接恢复期间将使用主机列表。有关详细信息,请参阅各个客户的文档指南。

在某些情况下,客户端可能无法在连接到其他节点后透明地继续操作。它们通常涉及托管在故障节点上的非镜像队列。

集群和可观察性

客户端连接,通道和队列将分布在群集节点上。运营人员需要能够跨所有集群节点检查和监控此类资源。

RabbitMQ CLI工具(例如rabbitmq-diagnostics和rabbitmqctl)提供检查资源和群集范围状态的命令。一些命令关注单个节点的状态(例如,rabbitmq-diagnostics环境和rabbitmq-diagnostics状态),其他命令检查群集范围的状态。后者的一些示例包括rabbitmqctl list_connections,rabbitmqctl list_mqtt_connections,rabbitmqctl list_stomp_connections,rabbitmqctl list_users,rabbitmqctl list_vhosts等。

这种“群集范围”命令通常首先联系一个节点,发现群集成员并将它们全部联系以检索和组合它们各自的状态。例如,rabbitmqctl list_connections将联系所有节点,检索其AMQP 0-9-1和AMQP 1.0连接,并将它们全部显示给用户。用户无需手动联系所有节点。假设集群的状态不变(例如,没有连接被关闭或打开),对两个不同节点一个接一个地执行的两个CLI命令将产生相同或语义相同的结果。但是,“节点本地”命令不会产生相同的结果,因为两个节点很少具有相同的状态:至少它们的节点名称会有所不同!

管理UI的工作方式类似:响应HTTP API请求的节点,将转发到其他集群成员并聚合其响应输出给用户。在具有启用了管理插件的多个节点的群集中,操作员可以使用任何节点来访问管理UI。对于使用HTTP API收集有关群集状态的数据的监视工具也是如此。无需依次向每个群集节点发出请求。

节点故障处理

服务器容忍个别节点的失败。节点可以随意启动和停止,只要它们可以联系关闭时已知的集群成员节点即可。

队列镜像允许跨多个群集节点复制队列内容。

非镜像队列也可以在群集中使用。节点故障时的非镜像队列行为取决于队列持久性。

RabbitMQ集群有几种处理网络分区的模式,主要是面向一致性。群集意味着跨LAN使用。建议不要跨WAN运行群集。Shovel或Federation插件是通过WAN连接服务器的更好解决方案。请注意,Shovel和Federation不等同于群集。

度量和统计

每个节点都存储并聚合自己的度量标准和统计信息,并为其他节点提供访问它的API。某些统计信息是群集范围的,其他统计信息特定于各个节点。响应HTTP API请求的节点与其对等方联系以检索其数据,然后生成聚合结果。

在早于3.6.7的版本中,RabbitMQ管理插件使用专用节点进行统计信息收集和聚合。

磁盘和内存节点

节点可以是磁盘节点或内存节点。(注意:磁盘和磁盘可互换使用)。内存节点仅将内部数据库表存储在内存中。这不包括消息,消息存储索引,队列索引和其他节点状态。

在绝大多数情况下,您希望所有节点都是磁盘节点;内存节点是一种特殊情况,可用于改进具有高性能队列,交换或绑定流失的性能群集。内存节点不提供更高的消息速率。如有疑问,请仅使用磁盘节点。

由于RAM节点仅将内部数据库表存储在RAM中,因此它们必须在启动时从对等节点同步它们。这意味着群集必须至少包含一个磁盘节点。因此,无法手动删除群集中的最后一个剩余磁盘节点。

用rabbitmqctl执行集群脚本

以下是跨三台机器手动设置和操作RabbitMQ集群的记录 -  rabbit1,rabbit2,rabbit3。建议在使用更多自动化构建群集之前研究该示例。

我们假设用户已登录到所有三台计算机,RabbitMQ已安装在计算机上,并且rabbitmq-server和rabbitmqctl脚本位于用户的PATH中。

可以修改此脚本以在单个主机上运行,​​如下面更详细说明。

启动独立节点

通过将现有RabbitMQ节点重新配置为群集配置来设置群集。因此,第一步是以正常方式在所有节点上启动RabbitMQ:

# on rabbit1
rabbitmq-server -detached
# on rabbit2
rabbitmq-server -detached
# on rabbit3
rabbitmq-server -detached

这将创建三个独立的RabbitMQ代理,每个节点一个,由cluster_status命令确认:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit2]}]},{running_nodes,[rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
# => ...done.

从rabbitmq-server shell脚本启动的RabbitMQ代理的节点名是rabbit @ shorthostname,其中短节点名称是小写的(如上面的rabbit @ rabbit1)。在Windows上,如果使用rabbitmq-server.bat批处理文件,则短节点名称为大写(如rabbit @ RABBIT1)。键入节点名称时,大小写很重要,并且这些字符串必须完全匹配。

创建集群

为了连接集群中的三个节点,我们告诉两个节点,比如rabbit@rabbit2和rabbit@rabbit3,加入第三个节点,比如rabbit@rabbit1。在此之前,必须重置两个新加入的成员。

我们首先将rabbit@rabbit2加入rabbit@rabbit1的群集中。为此,在Rabbit@rabbit2上,我们停止RabbitMQ应用程序并加入rabbit@rabbit1集群,然后重新启动RabbitMQ应用程序。请注意,必须先重置节点,然后才能加入现有群集。重置节点会删除以前在该节点上存在的所有资源和数据。这意味着节点不能成为群集的成员并同时保留其现有数据。如果需要,可以使用蓝/绿部署策略或备份和还原。

# on rabbit2
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.

rabbitmqctl reset
# => Resetting node rabbit@rabbit2 ...

rabbitmqctl join_cluster rabbit@rabbit1
# => Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.

rabbitmqctl start_app
# => Starting node rabbit@rabbit2 ...done.

通过在任一节点上运行cluster_status命令,我们可以看到两个节点在一个集群中连接:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

Now we join rabbit@rabbit3 to the same cluster. The steps are identical to the ones above, except this time we'll cluster to rabbit2 to demonstrate that the node chosen to cluster to does not matter - it is enough to provide one online node and the node will be clustered to the cluster that the specified node belongs to.现在我们将rabbit@rabbit3加入到同一个集群中。这些步骤与上面的步骤相同,除了这次我们将集群到rabbit2以证明选择集群的节点无关紧要 - 它足以提供一个在线节点,并且该节点将集群到集群中指定的节点属于。

# on rabbit3
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit3 ...done.

# on rabbit3
rabbitmqctl reset
# => Resetting node rabbit@rabbit3 ...

rabbitmqctl join_cluster rabbit@rabbit2
# => Clustering node rabbit@rabbit3 with rabbit@rabbit2 ...done.

rabbitmqctl start_app
# => Starting node rabbit@rabbit3 ...done.

We can see that the three nodes are joined in a cluster by running the cluster_status command on any of the nodes:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit3,rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit3,rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit3,rabbit@rabbit2,rabbit@rabbit1]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
# => ...done.

通过执行上述步骤,我们可以在群集运行时随时向群集添加新节点。

重启集群节点

已加入群集的节点可以随时停止。它们也可能失败或被操作系统终止。在所有情况下,群集的其余部分可以继续运行,当节点再次启动时,节点会自动“赶上”(同步)其他集群节点。请注意,某些分区处理策略可能以不同方式工作并影响其他节点

我们关闭节点rabbit@rabbit1和rabbit@rabbit3并检查每一步的集群状态:

# on rabbit1
rabbitmqctl stop
# => Stopping and halting node rabbit@rabbit1 ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit3,rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit3]}]
# => ...done.

# on rabbit3
rabbitmqctl stop
# => Stopping and halting node rabbit@rabbit3 ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit2]}]
# => ...done.

现在我们再次启动节点,检查群集状态:

# on rabbit1
rabbitmq-server -detached
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmq-server -detached

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
# => ...done.

了解进程节点在停止和重新启动时经历的非常重要。

停止节点选择一个在线集群成员(将仅考虑磁盘节点)以在重新启动后进行同步。 重启后,节点将默认尝试联系该对等体10次,响应超时30秒。如果对等体在该时间间隔内变得可用,则节点成功启动,从对等体同步它所需的内容并继续运行。如果对等方不可用,则重新启动的节点将放弃并自愿停止。

当一个节点在关机期间没有在线对等体时,它将在没有尝试与任何已知对等体同步的情况下启动。但是,它不是作为独立节点启动的,并且对等体将能够重新加入它。

在节点名称或主机名更改后重新加入的节点可以作为空节点启动;如果其数据目录路径因此而更改,则此类节点将无法重新加入群集。当节点脱机时,可以使用空白数据目录重置或启动其对等节点。在这种情况下,恢复节点也将无法重新加入其对等体,因为内部数据存储集群标识将不再匹配。

请考虑以下情形:

  1. 由3个节点A,B和C组成的集群
  2. A节点关闭
  3. B节点重置
  4. A重新启动
  5. 节点A尝试重新加入B,但B的集群标识已更改
  6. 节点B不会将A识别为已知的集群成员,因为它已被重置

在这种情况下,节点B将拒绝来自A的群集尝试,并在日志中显示相应的错误消息:

Node 'rabbit@node1.local' thinks it's clustered with node 'rabbit@node2.local', but 'rabbit@node2.local' disagrees

在这种情况下,B可以再次重置然后将能够加入A,或者A可以重置并且将成功加入B.

When the entire cluster is brought down therefore, the last node to go down is the only one that didn't have any running peers at the time of shutdown. That node can start without contacting any peers first. Since nodes will try to contact a known peer for up to 5 minutes (by default), nodes can be restarted in any order in that period of time. In this case they will rejoin each other one by one successfully. This window of time can be adjusted using two configuration settings:

因此,当整个集群关闭时,最后一个要关闭的节点是唯一一个在关闭时没有任何正在运行的节点的节点。该节点可以在不联系任何对等端的情况下启动。由于节点将尝试与已知对等方联系最多5分钟(默认情况下),因此可以在该时间段内以任何顺序重新启动节点。在这种情况下,他们将成功地一个接一个地重新加入。可以使用两个配置设置调整此时间窗口:

# wait for 60 seconds instead of 30
mnesia_table_loading_retry_timeout = 60000

# retry 15 times instead of 10
mnesia_table_loading_retry_limit = 15

通过调整这些设置并调整已知对等方必须返回的时间窗口,可以考虑可能超过5分钟完成的群集范围的重新部署方案。

在升级期间,有时最后一个要停止的节点必须是升级后要启动的第一个节点。该节点将被指定执行群集范围的模式迁移,其他节点可以从中重新加入并应用。

在某些情况下,无法恢复脱机的最后一个节点。可以使用forget_cluster_node rabbitmqctl命令从集群中删除它。

者,可以在节点上使用force_boot rabbitmqctl命令使其启动而不尝试与任何对等方同步(就好像它们最后一次关闭一样)。这通常仅在最后一个要关闭的节点或一组节点永远不会重新联机时才需要。

调整集群

有时需要从群集中删除节点。操作员必须使用rabbitmqctl命令显式执行此操作。

一些对等方发现机制支持节点运行状况检查和强制删除发现后端未知的节点。该功能是选择加入(默认情况下禁用)。

我们首先从集群中删除rabbit@rabbit3,将其恢复为独立操作。为此,在rabbit@rabbit3上,我们停止RabbitMQ应用程序,重置节点,然后重新启动RabbitMQ应用程序。

# on rabbit3
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit3 ...done.

rabbitmqctl reset
# => Resetting node rabbit@rabbit3 ...done.
rabbitmqctl start_app
# => Starting node rabbit@rabbit3 ...done.

请注意,将rabbit@rabbit3列为节点同样有效。

在节点上运行cluster_status命令确认rabbit@rabbit3现在不再是群集的一部分并且独立运行:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# => {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
# => ...done.

我们还可以远程删除节点。例如,当必须处理无响应的节点时,这很有用。例如,我们可以从rabbit@ rabbit2中移除rabbit@rabbi1。

# on rabbit1
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit1 ...done.

# on rabbit2
rabbitmqctl forget_cluster_node rabbit@rabbit1
# => Removing node rabbit@rabbit1 from cluster ...
# => ...done.

请注意,rabbit1仍然认为它与rabbit2集群,并且尝试启动它将导致错误。我们需要重置它才能再次启动它。

# on rabbit1
rabbitmqctl start_app
# => Starting node rabbit@rabbit1 ...
# => Error: inconsistent_cluster: Node rabbit@rabbit1 thinks it's clustered with node rabbit@rabbit2, but rabbit@rabbit2 disagrees

rabbitmqctl reset
# => Resetting node rabbit@rabbit1 ...done.

rabbitmqctl start_app
# => Starting node rabbit@mcnulty ...
# => ...done.

cluster_status命令现在显示作为独立RabbitMQ代理运行的所有三个节点:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit2]}]},{running_nodes,[rabbit@rabbit2]}]
# => ...done.

# on rabbit3
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit3 ...
# => [{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
# => ...done.

Note that rabbit@rabbit2 retains the residual state of the cluster, whereas rabbit@rabbit1 and rabbit@rabbit3 are freshly initialised RabbitMQ brokers. If we want to re-initialise rabbit@rabbit2we follow the same steps as for the other nodes:

注意,rabbit@rabbit2保留了集群的残留状态,而rabbit@ rabbit1和rabbit@rabbit3是刚刚初始化的RabbitMQ节点。如果我们想重新初始化rabbit@rabbit2,请按照与其他节点相同的步骤操作:

# on rabbit2
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.
rabbitmqctl reset
# => Resetting node rabbit@rabbit2 ...done.
rabbitmqctl start_app
# => Starting node rabbit@rabbit2 ...done.
        

除了rabbitmqctl forget_cluster_node命令和一些对等发现插件自动清理未知节点之外,没有RabbitMQ节点将从集群中永久删除其对等节点的情况。

升级集群

您可以在升级指南中找到有关升级群集的说明。

单机上的集群

在某些情况下,在单个计算机上运行RabbitMQ节点集群会很有用。这通常对于在台式机或笔记本电脑上试验群集非常有用,而无需为群集启动多个虚拟机。

为了在一台机器上运行多个RabbitMQ节点,必须确保节点具有不同的节点名称,数据存储位置,日志文件位置,并绑定到不同的端口,包括插件使用的端口。请参阅“配置”指南中的RABBITMQ_NODENAME,RABBITMQ_NODE_PORT和RABBITMQ_DIST_PORT,以及“文件和目录位置”指南中的RABBITMQ_MNESIA_DIR,RABBITMQ_CONFIG_FILE和RABBITMQ_LOG_BASE。

您可以通过重复调用rabbitmq-server(Windows上的rabbitmq-server.bat)手动在同一主机上启动多个节点。例如:

RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit rabbitmq-server -detached
RABBITMQ_NODE_PORT=5673 RABBITMQ_NODENAME=hare rabbitmq-server -detached
rabbitmqctl -n hare stop_app
rabbitmqctl -n hare join_cluster rabbit@`hostname -s`
rabbitmqctl -n hare start_app

将设置一个双节点集群,两个节点都作为磁盘节点。请注意,如果你让RabbitMQ打开AMQP以外的任何端口,你需要配置那些不会发生冲突的端口。这可以通过命令行完成:

RABBITMQ_NODE_PORT=5672 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15672}]" RABBITMQ_NODENAME=rabbit rabbitmq-server -detached
RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=hare rabbitmq-server -detached

安装管理插件后,将启动两个节点(然后可以群集)。

主机名更改

RabbitMQ节点使用主机名相互通信。因此,所有节点名称必须能够解析所有集群对等体的名称。对于像rabbitmqctl这样的工具也是如此。

除此之外,默认情况下,RabbitMQ使用系统的当前主机名命名数据库目录。如果主机名更改,则会创建一个新的空数据库。为避免数据丢失,设置固定且可解析的主机名至关重要。每当主机名更改时,必须重新启动RabbitMQ节点。

使用rabbit@localhost作为代理节点名称可以实现类似的效果。 此解决方案的影响是群集不起作用,因为所选主机名不会从远程主机解析为可路由地址。从远程主机调用时,rabbitmqctl命令同样会失败。没有这种弱点的更复杂的解决方案是使用DNS,例如如果在EC2上运行,则为Amazon Route 53。如果要使用nodename的完整主机名(RabbitMQ默认为短名称),并且可以使用DNS解析该完整主机名,则可能需要调查设置环境变量RABBITMQ_USE_LONGNAME = true。

有关更多信息,请参阅主机名解析部分。

防火墙节点

当节点位于数据中心或可靠网络中但由防火墙隔开时,存在防火墙群集节点的情况。同样,不建议通过WAN进行群集,也不建议在节点之间的网络链路不可靠时进行群集。

在最常见的配置中,您需要打开许多标准端口:

  • 4369: epmd, RabbitMQ节点和CLI工具使用的对等发现服务
  • 5672, 5671: 由AMQP 0-9-1和1.0客户端使用,启用和未启用TLS
  • 25672: 用于节点间和CLI工具通信(Erlang分发服务器端口)并从动态范围分配(默认情况下限于单个端口,计算为AMQP端口+ 20000)。除非确实需要这些端口上的外部连接(例如,群集使用federation或CLI工具在子网外的计算机上使用),否则不应公开这些端口。有关详情,请参阅网络指南
  • 35672-35682: CLI工具(Erlang分发客户端端口)用于与节点通信,并从动态范围(计算为服务器分发端口+ 10000到服务器分发端口+ 10010)分配。有关详情,请参阅网络指南
  • 15672: HTTP API 客户端, management UI 和 rabbitmqadmin (仅在启用管理插件时)
  • 61613, 61614: STOMP 客户端 启用和未启用TLS (仅在启用了STOMP插件)
  • 1883, 8883: MQTT 客户端 启用和未启用TLS, 如果启用了MQTT插件
  • 15674: STOMP-over-WebSockets 客户端(仅当启用了Web STOMP插件时)
  • 15675: MQTT-over-WebSockets 客户端 (仅当启用了Web MQTT插件时)

有关详细信息,请参阅RabbitMQ网络指南。

 

整个群集中的Erlang版本

集群中的所有节点必须运行相同的次要版本的Erlang:19.3.4和19.3.6可以混合使用。但19.0.1和19.3.6(或17.5和19.3.6)不能。各个Erlang / OTP补丁版本之间的兼容性因版本而异,但这种情况通常很少见。

从客户端连接到群集

客户端可以正常连接到群集中的任何节点。如果该节点发生故障,并且群集的其余部分仍然存在,则客户端应该注意到已关闭的连接,并且应该能够重新连接到群集中某个幸存的成员。通常,不建议将节点主机名或IP地址写死到客户端应用程序中:这会引入不灵活性,并且如果群集配置发生更改或群集中的节点数发生更改,则需要编辑,重新编译和重新部署客户端应用程序。相反,我们建议采用更抽象的方法:这可能是一个动态DNS服务,它具有非常短的TTL配置,或普通的TCP负载均衡器,或者通过心脏起搏器或类似技术实现的某种移动IP。通常,管理集群内节点连接的这一方面超出了RabbitMQ本身的范围,我们建议使用专门为解决这些问题而设计的其他技术。

具有RAM节点的集群

RAM节点仅将其元数据保存在内存中。由于RAM节点不必像磁盘节点那样写入磁盘,因此它们可以性能更好。但请注意,由于持久性队列数据始终存储在磁盘上,因此性能改进将仅影响资源管理(例如,添加/删除队列,交换或虚拟主机),但不会影响发布或消耗速度。

RAM节点是一个高级用例;设置第一个群集时,您应该不使用它们。您应该有足够的磁盘节点来处理冗余要求,然后在必要时添加额外的RAM节点以进行扩展。

仅包含RAM节点的集群是脆弱的;如果群集停止,您将无法再次启动它并将丢失所有数据。在许多情况下,RabbitMQ将阻止创建仅限RAM节点的集群,但它不能完全阻止它。

此处的示例仅显示具有一个磁盘和一个RAM节点的集群;这样的集群是一个糟糕的设计选择。

创建 RAM 节点

我们可以在第一次加入集群时将节点声明为RAM节点。我们像以前一样使用rabbitmqctl join_cluster执行此操作,但是传递--ram标志:

# on rabbit2
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.

rabbitmqctl join_cluster --ram rabbit@rabbit1
# => Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.

rabbitmqctl start_app
# => Starting node rabbit@rabbit2 ...done.

RAM节点在群集状态中显示如下:

# on rabbit1
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit1 ...
# => [{nodes,[{disc,[rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
# => ...done.

# on rabbit2
rabbitmqctl cluster_status
# => Cluster status of node rabbit@rabbit2 ...
# => [{nodes,[{disc,[rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
# =>  {running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
# => ...done.

更改节点类型

我们可以将节点的类型从ram更改为disc,反之亦然。假设我们想要反转rabbit@rabbit2和rabbit@rabbit1的类型,将前者从ram节点转换为盘节点,后者从盘节点转换为ram节点。为此,我们可以使用change_cluster_node_type命令。必须先停止节点。

# on rabbit2
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit2 ...done.

rabbitmqctl change_cluster_node_type disc
# => Turning rabbit@rabbit2 into a disc node ...
# => ...done.
# => Starting node rabbit@rabbit2 ...done.

# on rabbit1
rabbitmqctl stop_app
# => Stopping node rabbit@rabbit1 ...done.

rabbitmqctl change_cluster_node_type ram
# => Turning rabbit@rabbit1 into a ram node ...

rabbitmqctl start_app
# => Starting node rabbit@rabbit1 ...done.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值