【译】RabbitMQ集群搭建指南

集群指南

一个RabbitMQ broker是一个或多个Erlang 节点(nodes)的逻辑组,每一个都运行RabbitMQ应用,并共享用户,虚拟主机,队列,exchanges,etc。有时我们把节点的集合称之为一个集群

一个RabbitMQ broker操作所需的所有数据/状态会重复地穿过所有的节点,为了可靠性和伸缩性,包括完整的ACID属性。一个例外情况是消息队列,它们默认情况下只位于创建它们的节点上,尽管对于所有的节点它们都是可见并可访问的。要使得一个集群中的队列重复地贯穿节点,请参考关于高可用性的文档(注意你将首先需要一个工作的集群)。

RabbitMQ集群不能很好地忍受网络分割,因而不应该在WAN上使用它。shovel或federation插件是跨越一个WAN连接brokers的更好的解决方案。

一个集群的组成可以被动态地改变。所有的RabbitMQ borkers开始时运行在一个单独的节点上。这些节点可以被加入集群,随后再次回到独立的brokers状态。

RabbitMQ broker容忍独立节点的失败。节点可以随意地启动和停止。

一个节点可能是一个disk node或一个RAM node。(注意:diskdisc可互换使用。配置语法或状态消息常常使用disc。)在大多数情况下,你可能想要所有的节点都是disk nodes;RAM nodes是一种特殊的情况,以用来提升大规模集群的性能:参见下面RAM nodes的部分。

集群transcript

下面是贯穿三台机器建立并管理一个RabbitMQ集群的一个transcript - rabbit1, rabbit2, rabbit3

我们假设用户登入了所有的三台机器,它们都已经安装了RabbitMQ,而且rabbitmq-server和rabbitmqctl脚本都在用户的PATH内。

Erlang cookie

Erlang节点使用一个cookie来决定,它们之间是否被允许相互通信 - 对于两个能够通信的节点,它们必须具有相同的cookie。cookie只是一个字母数字的串。它们可以根据你的喜好而可长可短。

Erlang将在RabbitMQ服务器启动时自动地创建一个随机的cookie文件。最简单的处理方式就是,允许一个节点创建文件,然后把那个文件复制到集群中所有的其它机器上。

在Unix系统上,cookie将典型地位于/var/lib/rabbitmq/.erlang.cookie$HOME/.erlang.cookie

在Windows上,位置为:C:\Users\Current User\.erlang.cookie (%HOMEDRIVE% + %HOMEPATH%\.erlang.cookie)或者C:\Documents and Settings\Current User\.erlang.cookie, 和RabbitMQ Windows服务的C:\Windows\.erlang.cookie。如果使用了Windows服务,则cookie应该被同时放在这两个位置。

另外的一种方案,你可以在rabbitmq-serverrabbitmqctl脚本的erl调用中插入选项"-setcookie cookie"。

启动独立的节点

集群通过重新配置已经存在的RabbitMQ节点为一个集群配置来建立。因此,第一步是以通常的方法在所有节点上启动RabbitMQ:

rabbit1$ rabbitmq-server -detached
rabbit2$ rabbitmq-server -detached
rabbit3$ rabbitmq-server -detached
这将创建三个 独立的 RabbitMQ brokers,每个节点上一个,如同 cluster_status 命令所确认的那样:
rabbit1$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1]}]},{running_nodes,[rabbit@rabbit1]}]
...done.
rabbit2$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit2]}]},{running_nodes,[rabbit@rabbit2]}]
...done.
rabbit3$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit3 ...
[{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
...done.
rabbitmq-server shell脚本所启动的RabbitMQ broker的节点名字是 rabbit@shorthostname ,其中短的节点名字是小写的(如上面的 rabbit@rabbit1 中的那样 )。如果你是在Windows上使用 rabbitmq-server.bat批处理文件, 则短的节点名是大写的(比如, rabbit@RABBIT1 ) 。当你键入节点名字时,是大小写敏感的,而且这些字符串必须完全匹配。

创建集群

为了把我们的三个节点链入一个集群,我们告诉这些节点中的两个,比如rabbit@rabbit2rabbit@rabbit3,加入第三个的集群,比如rabbit@rabbit1

我们首先把rabbit@rabbit2加入rabbit@rabbit1的集群。要做到这一点,则在rabbit@rabbit2上,我们先停掉RabbitMQ应用,加入rabbit@rabbit1集群,然后重新启动RabbitMQ应用。注意,加入一个集群将隐式地重置节点,因而将移除那个节点上之前存在的所有的资源和数据。

rabbit2$ rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl join_cluster rabbit@rabbit1
Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.
rabbit2$ rabbitmqctl start_app
Starting node rabbit@rabbit2 ...done.

我们通过在这些节点中的一个上面运行cluster_status命令看到,两个节点被加入了一个集群:

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

现在我们把rabbit@rabbit3加入相同的集群。步骤与上面的一致,除了这一次我们选择了rabbit2来加入集群,以演示选择的具体节点对于加入集群无关紧要外 - 提供一个线上的节点足够了,然后节点将被加入那个特定节点所属的集群。

rabbit3$ rabbitmqctl stop_app
Stopping node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl join_cluster rabbit@rabbit2
Clustering node rabbit@rabbit3 with rabbit@rabbit2 ...done.
rabbit3$ rabbitmqctl start_app
Starting node rabbit@rabbit3 ...done.

我们可以通过在这些节点中的一个上面运行cluster_status命令,看到三个节点加入了一个集群:

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.
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.
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.

按照上面的步骤,我们可以在任何时候添加新的节点,即使是在集群运行的时候。

重启集群节点

已经被加入一个集群的节点可以在任何时候被停掉。它们crash时也不会出现问题。在这些情况下,集群中其余的节点将继续运行而不受影响,节点将在其它的那些集群节点再次启动时自动地"catch up"它们。

我们关闭了节点rabbit@rabbit1rabbit@rabbit3,在每一步时检查集群的状态:

rabbit1$ rabbitmqctl stop
Stopping and halting node rabbit@rabbit1 ...done.
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.
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.
rabbit3$ rabbitmqctl stop
Stopping and halting node rabbit@rabbit3 ...done.
rabbit2$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit2 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit2]}]
...done.

现在我们再次启动节点,并检查每一步时集群的状态:

rabbit1$ rabbitmq-server -detached
rabbit1$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
...done.
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.
rabbit3$ rabbitmq-server -detached
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.
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.
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.

一些重要的说明:

  • 当整个集群被停掉时,最后一个停掉的节点必须是第一个被加入线上的节点。如果不这样做,节点将在线上等待最后的disc节点恢复过来30秒,然后失败。如果最后的节点下线,而不能恢复回来,可以通过使用forget_cluster_node命令来把它移除出集群 - 请通过查找rabbitmqctl的manpage来获取更多的信息。
  • 如果所有的节点以不可控的方式同时停掉了(比如突然的断电),你将陷入这样的一种境况,所有的节点都认为有一些节点在它们之后被停掉。在这种情况下,你可以在一个节点上使用force_boot命令来使集群能够重新启动 - 请通过查找rabbitmqctl的manpage来获取更多的信息。

解体一个集群

当节点不再属于一个集群时,它们需要被显式地移除出去。我们首先将移rabbit@rabbit3除出集群,将它返回到独立执行的状态。要做到那些,我们在rabbit@rabbit3上停掉RabbitMQ应用,重置节点 ,然后重新启动RabbitMQ应用。

注意,那等效于把rabbit@rabbit3列为一个节点。

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

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

我们也可以远程地移除节点。这很有用,比如,我们不得不处理一个失去相应的节点。比如我们可以把rabbit@rabbit1rabbit@rabbit2移除出去。

rabbit1$ rabbitmqctl stop_app
Stopping node rabbit@rabbit1 ...done.
rabbit2$ rabbitmqctl forget_cluster_node rabbit@rabbit1
Removing node rabbit@rabbit1 from cluster ...
...done.

注意rabbit1仍然认为它与rabbit2是一个集群,并试图重启它,这将导致一个error。我们将需要重置它以能够再次启动它。

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
rabbit1$ rabbitmqctl reset
Resetting node rabbit@rabbit1 ...done.
rabbit1$ rabbitmqctl start_app
Starting node rabbit@mcnulty ...
...done.

现在cluster_status命令显示,三个节点都以独立的RabbitMQ brokers的方式在运行:

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

注意,rabbit@rabbit2保持了集群的剩余状态,尽管rabbit@rabbit1rabbit@rabbit3是被全新初始化的RabbitMQ brokers。如果我们想要重新初始化rabbit@rabbit2,我们可以按照相同的步骤来做:

rabbit2$ rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl reset
Resetting node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl start_app
Starting node rabbit@rabbit2 ...done.

自动配置一个集群

不使用cluster命令来"on the fly"地配置集群,集群也可以通过RabbitMQ配置文件来建立。rabbit应用中的配置文件应该将cluster_nodes设置为一个tuple,其中包含一个rabbit节点的列表,及一个atom - 值为disc或ram - 来表明节点将它们以一个disc节点还是非disc的角色加入。

如果指定了cluster_nodes,RabbitMQ将尝试与提供的每一个节点来组成集群,直到它与它们中的一个组成了集群。RabbitMQ将尝试与线上任何具有相同的Erlang和RabbitMQ版本号的节点组成集群。如果没有发现合适的节点,则本节点将处于未加入集群的状态。

注意,集群的配置只被应用于新节点。已经被重置或者第一次启动的节点才是一个新节点。因此,自动地建立集群不会发生在重启节点之后。这意味着,通过rabbitmqctl对加入集群所做的任何改动,将发生在自动地加入集群配置之前。

通过RabbitMQ配置文件来做集群配置的一个常见的应用是,自动地配置节点来加入一个公共的集群。为了实现这一点,可以在所有的集群上指定相同的集群节点。

比如,我们想要把我们上面例子里运行中的三个分离的节点加入一个单独的集群。首先我们要重置并 停止所有的节点,以确保它们都是新节点。

rabbit1$ rabbitmqctl stop_app
Stopping node rabbit@rabbit1 ...done.
rabbit1$ rabbitmqctl reset
Resetting node rabbit@rabbit1 ...done.
rabbit1$ rabbitmqctl stop
Stopping and halting node rabbit@rabbit1 ...done.
rabbit2$ rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl reset
Resetting node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl stop
Stopping and halting node rabbit@rabbit2 ...done.
rabbit3$ rabbitmqctl stop_app
Stopping node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl reset
Resetting node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl stop
Stopping and halting node rabbit@rabbit3 ...done.
现在我们在config文件中设置相关的字段:

[
  ...
  {rabbit, [
        ...
        {cluster_nodes, {['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3'], disc}},
        ...
  ]},
  ...
].

比如,如果这是我们所需要设置的唯一字段,我们将简单地创建包含如下这些内容的RabbitMQ config文件:

[{rabbit,
  [{cluster_nodes, {['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3'], disc}}]}].

(Erlang程序员及其他心怀好奇的人请注意:这是一个标准的Erlang配置文件。更多细节,请参考配置指南及Erlang Config Man Page。)

一旦我们把配置文件放在了适当的地方,我们就可以简单地来启动节点了:

rabbit1$ rabbitmq-server -detached
rabbit2$ rabbitmq-server -detached
rabbit3$ rabbitmq-server -detached

我们可以在这三个节点中的任何一个上面,通过执行命令cluster_status,来看到这三个节点加入了一个集群:

rabbit1$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]
...done.
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.
rabbit3$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit3 ...
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]},
 {running_nodes,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]
...done.

注意,为了从一个自动配置的集群中移除一个节点,它首先需要被从集群中的其它节点的RabbitMQ配置文件中移除出去。然后,可以安全地重置它。

升级集群

当把RabbitMQ从一个major或minor版本升级到另一个时(比如,从3.0.x到3.1.x或,从2.x.x到3.x.x),或者升级Erlang时,则必须先把整个集群停掉来升级(因为集群是不能运行在混合版本中的)。但从一个patch版本升级到另一个时(比如,从3.0.x到3.0.y)则不需要这样做;这些版本可以在一个集群中混合地运行(除了3.0.0不能与3.0.x系列中更新的版本混合外)。

当在major/minor版本之间升级时,RabbitMQ将在需要的时候自动地升级它的持久化数据结构。在一个集群中,这个任务由第一个被启动的disc节点来("upgrade"节点)执行。然而,当升级一个RabbitMQ集群时,你不应该首先启动任何RAM节点;启动的任何RAM节点将产生一个错误消息或启动失败。

尽管不是一定要遵守地,但最好提前决定哪一个disc节点将成为upgrader,然后最后停掉它,并首先启动它。否则正在停止的upgrader节点和上次停掉的节点之间对于集群配置所作的改动将丢失。

只有在RabbitMQ版本为2.1.1及之后才可以使用自动升级。如果你使用了更早的集群,你将需要重新构建它来升级。

单台机器上的集群

在某些情形下,在单台机器上运行一个RabbitMQ节点的集群可能是有用的。在一台桌面电脑或手提电脑上,没有为集群启动多台虚拟机器的费用,而又想要做实验研究集群时很有用。在单台机器上运行多于一个的节点的两个主要要做的是,每个节点应该有一个唯一的名字,并为每个使用的协议绑定到一个唯一的端口/IP地址组。

你可以在相同的主机上通过重复调用rabbitmq-server ( 在Windows上则是rabbitmq-server.bat)手动启动多个节点。你必须确保在每次调用时都给环境变量RABBITMQ_NODENAME和RABBITMQ_NODE_PORT设置了适当的值。

比如:

$ 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

将设置一个两节点的集群,它们都是disc节点。注意,如果你的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

当management插件安装时,这将启动两个节点(随后它们可以被加入集群)。

hostname的问题

RabbitMQ使用系统当前的主机名来命名数据库目录。如果主机名变了,将创建一个新的空的数据库。为了避免数据丢失,设置一个固定的且可解析的主机名很重要。比如:

sudo -s # become root
echo "rabbit" > /etc/hostname
echo "127.0.0.1 rabbit" >> /etc/hosts
hostname -F /etc/hostname
无论何时你改变了主机名,你都应该重新启动RabbitMQ:

$ /etc/init.d/rabbitmq-server restart

一个类似的效果可以通过使用作为broker节点名来实现。

这个方案的影响是,集群将无法工作,因为选择的主机名对于远程主机而言将无法解析为可路由的地址。类似地,在一个远程主机上调用rabbitmqctl命令将失败。想要不遭受这种脆弱性的一个更健壮的方案是使用DNS,比如如果运行EC2可以使用Amazon Route 53。如果你想要为你的节点名使用完整的主机名(RabbitMQ默认使用short name),并且那个主机名可使用DNS解析,你可以设置环境变量RABBITMQ_USE_LONGNAME=true。

开启了防火墙的节点

当节点在一个数据中心或在一个可靠的网络上时,开启了防火墙的集群节点出现,但被防火墙分割开的情形。再提一次,不建议在一个WAN或节点之间的连接不可靠时建立集群。

在大多数常见的配置中,你将需要打开4369或25672断开来给集群使用。

Erlang充分利用了一个Port Mapper Daemon (epmd)来解析一个集群中的节点名。默认的epmd端口是4369,但这可以通过使用ERL_EPMD_PORT环境变量来改变。所有的节点必须使用相同的端口。更详细的信息请参考Erlang epmd manpage。

一旦通过epmd解析了一个分布式的节点地址,其它的节点将试着使用Erlang分布式节点协议直接与那个地址通信。在RabbitMQ中这种通信默认的端口比RABBITMQ_NODE_PORT
大20000(比如,默认是25672).这可以通过使用RABBITMQ_DIST_PORT变量显式地设置 - 参见配置指南。

集群中Erlang的版本

一个集群中所有的节点必须运行相同的Erlang版本。

由客户端连接集群

一个客户端可以以通常的方式与集群内的任何节点连接。如果那个节点失败,而集群内的其它节点仍然活着,则客户端应该注意到关闭的连接,并应该能够重新连接集群中还活着的成员。通常,不建议在客户端应用代码中把节点主机名或IP地址写死:这引入了不灵活性,并将在集群的配置改变或集群中的节点数量改变时,需要重新编辑、重新编译及重新部署客户端应用。相反我们建议一个更抽象的方法:这可能是一个动态的具有一个非常短的TTL配置的DNS服务,或一个plain TCP负载均衡器,或通过pacemaker或类似的技术实现的某种可移动的IP。通常,管理到一个集群中的节点的连接这方面,超出了RabbitMQ本身的范围了,我们建议使用其它专门设计的技术来解决这些问题。

具有RAM节点的集群

RAM节点只在内存中保存它们的metadata。由于RAM节点不需要像disc节点那样频繁的写入磁盘,因而它们性能更好。然而,注意由于持久化的队列数据总是被保存在磁盘,性能的提升将只影响资源管理(比如添加/移除队列,exchanges,或vhosts),而不是发布和消费的速度。

RAM节点是一种高级的用法;当你第一次设置集群时,你应该简单地放弃使用它。你应该具有足够的disc节点来处理你的冗余需求,然后如果需要再添加额外的RAM节点来扩展。

一个只包含RAM节点的集群时脆弱的;如果集群停掉了,你将无法重启它,并将丢失所有的数据。RabbitMQ将在多种情形下阻止建立一个只包含RAM节点的集群,但它无法完全阻止它。

这里的例子为了简化,演示了一个具有disc和一个RAM节点的集群;这是一个糟糕的设计选择。

创建RAM节点

我们可以在一个节点第一次加入集群时声明它为一个RAM节点。如同前面所用的那些,我们通过rabbitmqctl join_cluster,但传给它--ram标记来做到那一点:

rabbit2$ rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl join_cluster --ram rabbit@rabbit1
Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.
rabbit2$ rabbitmqctl start_app
Starting node rabbit@rabbit2 ...done.

在集群状态中,RAM节点被显示为下面的这样:

rabbit1$ rabbitmqctl cluster_status
Cluster status of node rabbit@rabbit1 ...
[{nodes,[{disc,[rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
 {running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
...done.
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@rabbit2rabbit@rabbit1的类型,把前者从一个ram节点变为一个disc节点,并把后者从一个disc节点变为一个ram节点。要做到这些,我们可以使用change_cluster_node_type命令。首先要停掉节点。

rabbit2$ rabbitmqctl stop_app
Stopping node rabbit@rabbit2 ...done.
rabbit2$ rabbitmqctl change_cluster_node_type disc
Turning rabbit@rabbit2 into a disc node ...
...done.
Starting node rabbit@rabbit2 ...done.
rabbit1$ rabbitmqctl stop_app
Stopping node rabbit@rabbit1 ...done.
rabbit1$ rabbitmqctl change_cluster_node_type ram
Turning rabbit@rabbit1 into a ram node ...
rabbit1$ rabbitmqctl start_app
Starting node rabbit@rabbit1 ...done.

Done。

原文链接。

你可能感兴趣的:(【译】RabbitMQ集群搭建指南)