赞
踩
一、集群简介
一个RabbitMQ broker是一个或者几个Erlang节点的一个逻辑分组,每个节点运行着RabbitMQ应用和共享用户、虚拟主机、队列、交换机等等。有时候我们把这些节点集合作为集群。
为了做到可靠、可扩展和ACID属性,所有数据或者状态都需要RabbitMQ broker复制到所有节点。对此,一个例外是消息队列,默认驻留在创建它们的节点上,虽然它们对于所有节点都是可访问和可见的。通过节点在集群内复制队列,可以参见这里(需要注意的是首先必须是集群)。
RabbitMQ不能很好的处理分区容忍,所以它不能用于WAN。shovel或者federation插件很能很好的解决这个问题。
集群的配置能够被动态地改变。所有RabbitMQ broker在一个单独的节点上开始运行,这些节点能够被加入到集群中,随后又能转换成单独的broker。
RabbitMQ broker容忍个别节点的失败。节点能够被随意的启动和停止。
一个节点可以是磁盘节点或者内存节点(注意:disk和disc在使用上是可交换的,配置语法或者状态消息通常使用disc)。内存节点保持它们的状态仅仅在内存中(队列内容除外,如果队列持久化或者太大不能放在内存中则驻留在磁盘上)。磁盘节点保持状态在内存中和磁盘上。内存节点不会像磁盘节点一样写入到磁盘,因此性能更佳。然而,需要注意的是队列数据一直存储在磁盘上,性能的提升仅仅影响到资源管理(例如:添加/删除队列、交换机、或者虚拟机),而不是发布和消费速度。因为状态复制到集群内所有节点,所以集群内可以只有一个磁盘节点(但是不推荐)用于存储集群状态。
二、集群副本
接下来是一个设置和操作RabbitMQ集群的副本,其通过三台机器构成一个集群,分别是rabbit1、rabbit2、rabbit3,其中两台机器复制数据到内存和磁盘,另外一台仅仅复制数据到内存中。
我们假设用户登录到所有的三台机器上,RabbitMQ已经安装到机器上了,rabbitmq-server和rabbitmqctl脚本已经在用户PATH里了。
1、初始化设置
Erlang节点使用cookie来检测它们之间是否允许通信,如果两个节点能够通信,那么它们必须拥有相同的cookie。
Cookie仅仅是一个含有文字与数字的字符串,如果你喜欢其可以是long或者short。
RabbitMQ服务器启动的时候,Erlang将自动创建随机cookie文件。这个文件一般位于/var/lib/rabbitmq/.erlang.cookie。最简单的方式是允许其中一个节点创建cookie文件,然后将其拷贝到集群内所有其它节点。
作为一种选择,你可以在调用rabbitmq-server和rabbitmqctl脚本时插入选项“-setcookie cookie”。
2、启动独立节点
用正常的方式在所有节点上启动RabbitMQ,具体如下:
rabbit1$ rabbitmq-server -detached
rabbit2$ rabbitmq-server -detached
rabbit3$ rabbitmq-server -detached
如此,则创建了三个独立的RabbitMQ broker,每个节点上一个,可以通过如下命令查看集群状态:
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...
...done.
3、创建集群
为了将三个节点连入集群中,我们将其中两个节点加入到第三个节点的集群中,比如:将rabbit@rabbit2和rabbit@rabbit3加入到rabbit@rabbit1。
我们首先将rabbit@rabbit2作为内存节点加入到rabbit@rabbit1的集群中,如下操作即可达到目的:
rabbitmqctl stop_appStopping node rabbit@rabbit2 ...done.
rabbitmqctl join_cluster --ram rabbit@rabbit1Clustering node rabbit@rabbit2 with [rabbit@rabbit1] ...done.
rabbitmqctl start_appStarting node rabbit@rabbit2 ...done.
需要注意的是加入一个集群会隐式重启该节点,因此节点上之前存在的资源和数据都会被删除。
在任意节点上运行rabbitmqctl cluster_status都会看到这两个节点已经一个集群中了,具体如下:
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...
{running_nodes,[rabbit@rabbit2,rabbit@rabbit1]}]
rabbit2$
[{nodes,[{disc,[rabbit@rabbit1]},{ram,[rabbit@rabbit2]}]},
...done.
现在我们可以将rabbit@rabbit3以磁盘节点模式加入相同的集群。加入步骤跟上面类似,但不同的是要删除—ram标志,因为默认就是磁盘节点模式。实际上,在将节点加入集群时,可以选择集群内任何在线节点,而不一定是rabbit@rabbit1,这里选择的就是rabbit@rabbit2,具体请看如下:
rabbitmqctl stop_appStopping node rabbit@rabbit3 ...done.
rabbitmqctl join_cluster rabbit@rabbit2Clustering node rabbit@rabbit3 with rabbit@rabbit2 ...done.
rabbitmqctl start_appStarting node rabbit@rabbit3 ...done.
同样,在任意节点上运行rabbitmqctl cluster_status都会看到这三个节点已经一个集群中了,具体如下:
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...
{running_nodes,[rabbit@rabbit3,rabbit@rabbit2,rabbit@rabbit1]}]
rabbit2$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit3]},{ram,[rabbit@rabbit2]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...
{running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
rabbit2$
rabbit2$
...done.
rabbit3$
rabbit3$
rabbit3$
rabbit1$
rabbit2$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...
{running_nodes,[rabbit@rabbit2,rabbit@rabbit3]}]
rabbit3$
rabbit2$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
现在我们再次启动这两个节点,然后检查集群状态,具体如下:
rabbitmq-server -detachedrabbit1$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...
{running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
rabbit3$
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...
{running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
rabbit2$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...
{running_nodes,[rabbit@rabbit2,rabbit@rabbit1,rabbit@rabbit3]}]
rabbit3$
rabbit3$
rabbit3$
rabbit1$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...
{running_nodes,[rabbit@rabbit1,rabbit@rabbit2]}]
rabbit3$
[{nodes,[{disc,[rabbit@rabbit3]}]},{running_nodes,[rabbit@rabbit3]}]
rabbit1$
rabbit2$
...done.
需要注意的是此时rabbit@rabbit1任然认为其还在rabbit@rabbit2的集群中,但是当尝试着启动它时会返回错误。我们需要重置它已让其可以再次被启动:
rabbitmqctl start_appStarting node rabbit@rabbit1 ...
rabbit1$
rabbit1$
...done.
再次运行分别在三个节点上运行rabbitmqctl cluster_status命令,会发现它们都各自独立运行着RabbitMQ broker:
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit1 ...
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit3 ...
...done.
需要注意的是rabbit@rabbit2此时仍保持着集群的残余状态,然而rabbit@rabbit1和rabbit@rabbit3的RabbitMQ broker则是清新的初始状态。如果我们想让rabbit@rabbit2也这样需要其执行相同的步骤:
rabbitmqctl stop_appStopping node rabbit@rabbit2 ...done.
rabbitmqctl resetResetting node rabbit@rabbit2 ...done.
rabbitmqctl start_appStarting node rabbit@rabbit2 ...done.
7、自动配置集群
除了通过命令可以实现集群外,还可以通过配置文件来实现集群,配置文件可以参看这里,也可以参看这里。在该文件中设置cluster_nodes域,该域是一个tuple包含一个节点列表,一个atom指示是磁盘还是内存节点。
如果cluster_nodes被指定,RabbitMQ将尝试着集群节点列表中所有拥有相同Erlang和RabbitMQ版本的在线节点。
需要注意的是集群配置仅仅应用于新节点。新节点是指刚被重置或者第一次启动的节点。因此,自动集群不会在重启节点后立即生效。这意味着通过rabbitmqctl对集群发生的任何改变都优先于自动集群配置。
下面我们将演示如何把三个独立的节点加入集群,其中rabbit@rabbit1和rabbit@rabbit2为磁盘节点,为了确保所有节点的干净,首先我们需要重置和停止所有节点,具体如下:
rabbitmqctl stop_appStopping node rabbit@rabbit1 ...done.
rabbitmqctl resetResetting node rabbit@rabbit1 ...done.
rabbitmqctl stopStopping and halting node rabbit@rabbit1 ...done.
rabbitmqctl stop_appStopping node rabbit@rabbit2 ...done.
rabbitmqctl resetResetting node rabbit@rabbit2 ...done.
rabbitmqctl stopStopping and halting node rabbit@rabbit2 ...done.
rabbitmqctl stop_appStopping node rabbit@rabbit3 ...done.
rabbitmqctl resetResetting node rabbit@rabbit3 ...done.
rabbitmqctl stopStopping and halting node rabbit@rabbit3 ...done.
现在我们设置配置文件中重要的域,具体如下:
...
...
...
...
[
{rabbit, [
{cluster_nodes, {['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3'], ram}},
]},
].
这是标准的Erlang配置文件,更多详细信息可以参看RabbitMQ配置向导和Erlang配置帮助。
如果修改了配置文件,可以简单地启动节点:
rabbitmq-server -detachedrabbit2$
rabbitmq-server -detachedrabbit1$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
rabbitmqctl cluster_statusCluster status of node rabbit@rabbit2 ...
{running_nodes,[rabbit@rabbit1,rabbit@rabbit2,rabbit@rabbit3]}]
rabbit3$
[{nodes,[{disc,[rabbit@rabbit1,rabbit@rabbit2]},{ram,[rabbit@rabbit3]}]},
...done.
需要注意的是:为了从自动集群配置中移除一个节点,首先需要从集群中别的节点的配置文件中将其移除。
三、升级集群
当RabbitMQ升级major或者minor版本时(比如:从3.0.x到3.1.x或者从2.x.x到3.x.x),或者升级Erlang时,整个集群必须停掉。但是当升级RabbitMQ补丁(例如:从3.0.x到3.0.y)时就不需要这样。这些版本都能被固化到集群中(但是除了3.0.0及后来的3.0.x系列)。
当RabbitMQ升级major或者minor版本时,如果必要RabbitMQ将自动更新其持久化的数据结构。在集群中,这项任务由第一个启动的磁盘节点来执行。因此,当升级RabbitMQ集群时,不应该尝试启动任何内存节点,任何内存节点启动时都会发出一个错误消息然后失败。
提前停止即将升级的磁盘节点,并在升级完后首先启动它,这是个好主意,但这不是绝对必须的。否则,在升级节点停止和最后节点停止之间,集群配置的改变将会丢失。
只有RabbitMQ 2.1.1及其以后版本可以自动升级,如果有更早版本的集群,你需要重建集群来完成升级。
四、单机器集群
在某些环境下,在单机器上运行集群的所有节点是很有用的。非常典型的应用是:在桌面或便携式机器上通过启动几个虚拟机来实验集群。在单机器上运行多个节点有两个主要的要求:(1)每个节点有唯一的名称;(2)针对每种协议,每个节点绑定到唯一的IP和端口号对。
可以通过手动重复调用rabbitmq-server来在同一主机上启动多个节点。必须确保每次调用时设置的环境变量RABBITMQ_NODENAME和RABBITMQ_NODE_PORT都有合适的值。例如:
$ RABBITMQ_NODE_PORT=5673 RABBITMQ_NODENAME=hare rabbitmq-server -detached
$ rabbitmqctl -n hare join_cluster rabbit@`hostname -s`
<span color:#333333;"="" style="word-wrap: break-word; font-size: 10pt;">$ rabbitmqctl -n hare start_app
上面将建立两个节点的集群。
五、防火墙节点
防火墙集群节点的经典案例是:节点在数据中心或者可信网络中,但是被防火墙分离。同样,不推荐在WAN或者不可信网络上架设集群。
如果集群中不同节点在同一数据中心,但是在防火墙后面,这样就必须修改配置以确保是内部节点通信。Erlang使用empd(Erlang Port Mapper Daemon)来解析集群内节点名称。
缺省epmd端口号是4369,但是可以通过环境变量ERL_EPMD_PORT改变其值。所有节点必须使用同样的端口号。防火墙必须允许集群内节点在这个端口上传输数据。更详细的信息请参看Erlang epmd帮助。
一旦分布式Erlang节点地址通过epmd已经被解析了,其它节点将通过Erlang分布式节点协议尝试使用该地址直接通信。通信端口号范围可以通过Erlang内核APP的两个参数来配置:
inet_dist_listen_min
inet_dist_listen_max
防火墙必须允许集群内节点通过这个范围内的端口号传递数据(假设所有节点使用同样的端口号范围)。缺省端口号范围不受限制。更详细的信息可以参看Erlang内核APP帮助。
六、客户端连接集群
客户端可以连接集群内任何节点。如果被连接节点崩溃但是集群内其它节点还健在,则客户端通知连接关闭,然后重连集群内其它节点。通常,将节点主机名或者IP地址写死在客户端APP中是不合适的,这会导致当集群配置改变或者集群节点数改变时,客户端需要重新编辑、编译、部署。相反,建议更抽象的方式:可以是动态DNS服务,其有简短的TTL配置,或者TCP负载均衡,或者移动IP排序或者相似技术。一般,管理集群内节点的连接已经非RabbitMQ本身能力所及,建议使用其它技术来解决此类问题。
七、注意事项
1、host问题
集群节点之间能够互相访问,因此,每个集群节点的host文件中都需要配置集群内所有节点的信息,以保证能互相解析,具体如下:
#vi /etc/hosts
172.28.14.223 ZS-QA-01
172.28.14.224 ZS-QA-02
172.28.14.225 ZS-QA-03
比如:3个节点的集群,172.28.14.223/224/225三台机器的hostname分别是ZS-QA-01/02/03。
如果不知道本机hostname可以通过以下命令查看:
#cat /proc/sys/kernel/hostname
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。