rabbitmq的broker是一个或者几个erlang node的逻辑分组,每个运行rabbitmq应用的node都共享user、vhost、queue、exchange等等,我们称这些node为cluster。所有rabbitmq broker上的全部data/state都必须在所有的node之间可以复制,这是为了集群的可靠性和可扩展性,完全符合ACID的特性。但是queue是一个例外,queue默认只存在于创建它的node上面,虽然queue对于其他node是可见且可达的。
rabbitmq cluster不能处理网络分区的情况,所以它不能用于WAN环境。要处理在WAN直接的数据传输,请看下一章的federation,federation是在两个cluster直接复制数据的。cluster的构成是可以动态变化的,所有的brokers开始启动时都是在一个单独的node上启动的,这些node可以加入到cluster中,也可以从cluster中脱离出来。brokers可以承受单个nodes的失效,node可以随意的start和stop。
一个node的类型可以是disk或者ram类型。ram nodes在内存中保存它们的状态信息,不过queue的内容有点特殊,如果将queue的属性设置为持久化或者内容在内存中太大时,它会被存放到disk上。disk node在内存和硬盘上同时保存它的状态信息。ram nodes不会像disk nodes一样把信息写到硬盘上的,所以ram nodes的性能会更好一些。然而,并不因为queue的数据总是保存在硬盘上,性能提高只能通过资源管理来提升,还要考虑publishing和consuming的速度影响,因为状态会在集群中所有的nodes之间复制,所以在一个cluster中可以只配置一个disk node,就可以安全的存储cluster的状态,但是并不建议这样做。
下面开始实战,环境还是<<Rabbitmq学习之路1-基本概念>>
ubuntu12.04 3台,其中两台是disk node,一台是ram node。关于rabbitmq的安装,请参考<<Rabbitmq学习之路1-基本概念>>。
node之间的通信是通过erlang node实现的,erlang node通过cookie来判断节点之间是否可以通讯,两个node必须有相同的cookie才能够通讯,cookie是一个由数字和字母组成的字符串。erlang启动后,会在/var/lib/rabbitmq/.erlang.cookie文件里面创建cookie。所以我们只要把某一个node的cookie文件复制到其他两台机器上相同的位置即可。也可以在rabbitmqctl命令中使用-setcookie cookie来在启动时设置cookie。
1 在三台机器上启动rabbitmq
/etc/init.d/rabbitmq start
注意:你这样只是启动了三个独立的rabbitmq broker,目前三台机器还不在一个cluster中
2 确认三台机器启动后的状态
rabbitmqctl cluster_status
注意:rabbitmq broker默认的node的名字是rabbit@shorthostname的格式。其中shorthostname在linux系统下是你的小写的主机名。
3 创建cluster
将 ubuntuTest03和 ubuntuTest02加入到 ubuntuTest01的cluster中。
1 先将rabbit@ ubuntuTest02作为ram node加入到rabbit@ ubuntuTest01中(在 ubuntuTest02上操作):
- 1 先停止 ubuntuTest02上的rabbitmq应用
- rabbitmqctl stop_app
- 2 ubuntuTest02以ram node加入cluster
- rabbitmqctl join_cluster --ram rabbit@ubuntuTest01
- 3 启动rabbitmq应用
- rabbitmqctl start_app
2 在 ubuntuTest01或者 ubuntuTest02上验证cluster的状态
rabbitmqctl cluster_status
可以看到输出结果中显示cluster中已经有两台node了,而且显示了每个node的类型是disk还是ram的。
3 接下来将rabbit@ ubuntuTest03以disk node加入到 ubuntuTest01和 ubuntuTest02组成的cluster中。 ubuntuTest03加入 ubuntuTest01或者 ubuntuTest02的效果都是一样的,因为它俩在一个cluster中。
- # 还是基本的三步
- 1 rabbitmqctl stop_app
- 2 rabbitmqctl join_cluster rabbit@ubuntuTest02
- 3 rabbitmqctl start_app
注意:如果join参数不加--ram参数,则默认是以disk类型加入cluster的
4 在三台node中的随便某一台验证结果
rabbitmqctl cluster_status
4 有时候我们需要根据cluster的状态改变node的类型,例如
ubuntuTest02修改为disk类型,在 ubuntuTest02上执行以下命令:
- # 也是三步
- 1 rabbitmqctl stop_app
- 2 rabbitmqctl change_cluster_node_type disc
- 3 rabbitmqctl start_app
注意:在一个cluster中必须最少有一个disk类型的node,不允许全部是ram类型的node,否则会启动失败
5 cluster中的node可以被随意的停止和启动,他们并不影响cluster中的其他node的运行,node重启后会自动的和cluster中的其他node进行联系的。当cluster不能工作时,最后一个失效的node必须是重建后第一个开始工作的node,如果这种情况不满足,则所有的node则会为最后一个disk node的恢复等待30秒,如果最后一个失效的node无法重新工作,我们需要通过命令将其从cluster中移除。
6 脱离cluster
node可以加入cluster中,也能从cluster中脱离,我们将 ubuntuTest03从cluster中移除,以下在 ubuntuTest03上操作:
- # 也是分三步
- 1 rabbitmqctl stop_app
- 2 rabbitmqctl rest
- 3 rabbitmqctl start_app
这时我们在 ubuntuTest01和 ubuntuTest02上使用rabbitmqctl cluster_status查看状态,发现 ubuntuTest03已经不在cluster中了。
你也可以在某一台node上面让cluster中的其他node脱离cluster,比如在 ubuntuTest02上让 ubuntuTest01脱离cluster:
- 1 rabbitmqctl stop_app
- 2 rabbitmqctl forget_cluster_node rabbit@ubuntuTest01
注意:这时候
ubuntuTest01还是认为自己和 ubuntuTest02在一个cluster中,我们这时候需要在 ubuntuTest01重置状态
- 1 rabbitmqctl start_app
- 2 rabbitmqctl reset
- 3 rabbitmqctl start_app
- # 在执行第一步的时候,会发现报错,这就是因为ubuntuTest01还认为它在集群中