本文说的RabbitMQ集群,指的是镜像队列集群,搭建步骤网上很多,就不在赘述了,这里主要讲一下概念及优化。
1.重要参数
disk_free_limit:磁盘低水位线,若磁盘容量低于指定值则停止接收数据。存储模式为硬盘时有意义。可以指定绝对值,也可以设置相对于机器中的RAM的可用空间限制。默认值为1.0,表示将磁盘可用空间限制设置为与机器上的RAM数量相同。注意设置低于1.0的值很危险,应谨慎使用。
vm_memory_high_watermark:内存低水位线,若磁盘容量低于指定值则开启流控机制停止接收数据。存储模式为内存时有意义。默认值是0.4,即内存总量的40%。RabbitMQ使用内存超过40%的时候,会发出内存警告,阻塞所有发布消息的连接,一旦警告解除服务会恢复正常。它并不会阻止RabbitMQ Server使用不到40%,仅仅意味着到达这个点的时候,发布者会被阻塞block。
2.rabbitmq的集群和镜像队列区别
几个rabbitmq node进行了集群后,这些node 之间是可以同步元数据的,包括exchange的元数据、queue的元数据、binding的元数据等。但是默认情况下,不会同步queue的内容。因为如果同步的queue的内容,可能有这样的场景,queue很多并且每一个queue的内容都很大,rabbitmq需要忙着处理这些本node的queue还要负责处理和不同的node之前进行同步,这会造成系统很大负载,对rabbitmq的性能会有的影响,因此默认是关闭的。但是如果需要实现高可用,就需要打开镜像队列,这个时候集群之间就会同步queue的内容了。
镜像队列其实就是原来channel只会按照binding来把消息路由给某个队列,现在如果你使用了镜像队列,那么channel就需要并行的把消息路由给master node 同时还需要把消息同步给slave node上,所以当使用镜像队列以后性能是一定会下降的。
另外说下rabbitmq的集群node中必须有一个要配置为磁盘类型,这个是防止数据丢失的。
3.queue的master和slave node
每一个queue都有一个home node也叫主队列。所有的镜像操作首先必须要通过这个master,然后在复制到其他的mirrors上,这样做主要是为了保证消息的FIFO顺序,也就是说所有顺序执行的操作都要顺序交给master,然后channel在同步给slave node,如果master上移出了队列中的内容,那么所有的slave node也同步的移出所有的队列内容。但是要记住consumer消费的只是 master node,并不是slave node。
4.集群的启动
rabbitmq-server启动时,会一起启动节点和应用,它预先设置RabbitMQ应用为standalone模式。要将一个节点加入到现有的集群中,你需要停止这个应用,并将节点设置为原始状态。如果使用./rabbitmqctl stop,应用和节点都将被关闭。所以使用rabbitmqctl stop_app仅仅关闭应用。
两个rabbitmq集群重用的命令:reset 可以把一个node从一个集群中移出,forget_cluster_node则是可以在另一个节点上把某一个node移出自己的集群。
5.镜像队列知识要点
在使用镜像队列之前,有几点注意事项必须熟记于心:
1) 镜像队列不能作为负载均衡使用,因为每个操作在所有节点都要做一遍。
2) 将新节点加入已存在的镜像队列时,默认情况下ha-sync-mode=manual,镜像队列中的消息不会主动同步到新节点,除非显式调用同步命令。当 调用同步命令(via rabbitmqctl or web-based ui)后,队列开始阻塞,无法对其进行操作,直到同步完毕。当ha-sync-mode=automatic时,新加入节点时会默认同步已知的镜像队列。 由于同步过程的限制,所以不建议在生产环境的active队列(有生产消费消息)中操作。
3) 每当一个节点加入或者重新加入(例如从网络分区中恢复回来)镜像队列,之前保存的队列内容会被清空。
4) 镜像队列有主从之分,一个主节点(master),0个或多个从节点(slave)。当master宕掉后,会在slave中选举新的master。选举算法为最早启动的节点。
5) 整个集群都停掉了那么应该要保证最后一个down掉的node首先被启动。镜像队列中最后一个停止的节点会是master,启动顺序必须是master先起。如果slave先起,它会有30秒的等待时间,等待master启动, 然后加入cluster。当所有节点因故(断电等)同时离线时,每个节点都认为自己不是最后一个停止的节点。要恢复镜像队列,可以尝试在30秒之内同时启 动所有节点。
6) 对于镜像队列,客户端basic.publish操作会同步到所有节点;而其他操作则是通过master中转,再由master将操作作用于salve。 比如一个basic.get操作,假如客户端与slave建立了TCP连接,首先是slave将basic.get请求发送至master,由 master备好数据,返回至slave,投递给消费者。