集群文字记录(Transcript)
下面是通过三台机器-rabbit1, rabbit2, rabbit3来设置和操作RabbitMQ集群的文字记录.
我们假设用户已经登录到这三台机器上,并且都已经在机器上安装了RabbitMQ,以及rabbitmq-server 和rabbitmqctl 脚本都已经在用户的PATH环境变量中.
This transcript can be modified to run on a single host, as explained more details below.
节点(以及CLI工具)之间如何来认证: Erlang Cookie
RabbitMQ 节点和CLI 工具(如rabbitmqctl) 使用cookie来确定每个节点之间是否可以通信. 两个节点之间要能通信,它们必须要有相同的共享密钥Erlang cookie. cookie只是具有字母数字特征的字符串。只要你喜欢,它可长可短. 每个集群节点必须有相同的cookie.
当RabbitMQ 服务器启动时,Erlang VM 会自动地创建一个随机的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 service其位置在C:\Windows\.erlang.cookie。如果使用了Windows service , cookie可被放于这两个位置中.
作为替代方案,你可以在 rabbitmq-server 和 rabbitmqctl 脚本中调用erl时,插入"-setcookie cookie"选项.
当cookie未配置时 (例如,不相同), RabbitMQ 会记录这样的错误"Connection attempt from disallowed node" and "Could not auto-cluster".
启动独立节点
集群可通过重新配置,而将现有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@rabbit2 和 rabbit@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.
通过上面的步骤,当集群运行的时候,我们可以在任何时候将新的节点加入到集群中.
重启集群节点
注意,加入到集群中的节点可在任何时候停止, 对于崩溃来说也没有问题. 在这两种情况下,集群剩余的节点将不受影响地继续操作,当它们重启的时候,这些崩溃的节点会再次自动追赶上其它的集群节点。
我们关闭了节点rabbit@rabbit1和rabbit@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节点后,运行的节点已经没有rabbit1节点了
现在我们再次启动节点,并检查集群状态:
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.
这里有一些重要的警告:
- 当整个集群崩溃的时候, 最后一个崩溃的节点必须第一个上线.如果不是这样,节点将会等待最后一个磁盘节点30秒以确认其重新上线,否则就会失败. 如果最后一个下线的节点,不能再重新上线,那么它可能会使用forget_cluster_node命令来从集群中删除 - 查阅 rabbitmqctl页面来了解更多信息.
- 如果所有集群节点都在同一个时间内停止且不受控制(如断电)。在这种情况下,你可以在某个节点上使用force_boot命令使其再次成为可启动的-查阅 rabbitmqctl页面来了解更多信息.
脱离集群
当节点不再是集群的一部分时,可以明确地将其从集群中删除. 首先我们将节点rabbit@rabbit3从集群中删除, 以使其回归独立操作.要做到这一点,需要在rabbit@rabbit3节点上停止RabbitMQ 应用程序,重设节点,并重启RabbitMQ应用程序.
rabbit3$ rabbitmqctl stop_app
Stopping node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl reset
Resetting node rabbit@rabbit3 ...done.
rabbit3$ rabbitmqctl start_app
Starting node rabbit@rabbit3 ...done.
在节点上运行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@rabbit2中删除rabbit@rabbi1.
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处在一个集群中,但尝试启动时会出现一个错误.这时,我们需要对其进行重置以使其能再次启动.
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 命令会显示三个节点都是独立节点,并且操作是独立的:
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@rabbit1 和rabbit@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.
单台机器上的集群
在某些情况下,在一台机器上运行RabbitMQ节点的集群是有用的(试验性质).
要在一台机器上运行多个RabbitMQ节点,必须确保节点含有不同的节点名称,数据存储路径,日志文件位置,绑定到不同的端口,并包含那些插件使用的端口等等 .参考配置指南中的RABBITMQ_NODENAME, RABBITMQ_NODE_PORT, 和 RABBITMQ_DIST_PORT文档 ,以及 File and Directory Locations guide指南中的 RABBITMQ_MNESIA_DIR, RABBITMQ_CONFIG_FILE, and RABBITMQ_LOG_BASE。
你可以在同一个主机上通过重复调用rabbitmq-server(rabbitmq-server.bat on Windows)来手动地启动多个节点 . 例如:
$ 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
这会设置两个节点的集群,这两个节点都是磁盘节点. 注意,如果你想打开非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 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.
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.
改变节点类型
我们可以将节点的类型从磁盘修改为内存,反之亦然. 假设我们想反转rabbit@rabbit2 和 rabbit@rabbit1的节点类型,即先将内存节点转换为磁盘节点,随后再将其从磁盘节点转换为内存节点.要做到这点,我们可以使用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.