参考:https://www.cnblogs.com/kevingrace/p/8012792.html
RabbitMQ集群基础
Rabbit集群模式大概分为以下三种:单一模式、普通模式、镜像模式
单一模式:最简单的情况,非集群模式,nothing to say.
普通模式:默认的集群模式。对于Queue来说,消息实体只存在于其中一个节点,A、B两个节点仅有相同的元数据,即队列结构。 当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。 所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连A或B,出口总在A,会产生瓶颈。该模式存在一个问题就是当A节点故障后,B节点无法取到A节点中还未消费的消息实体。 如果做了消息持久化,那么得等A节点恢复,然后才可被消费;如果没有持久化的话,消息会丢失。
镜像模式:把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案。该模式解决了上述问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用于该模式(比如下面图中介绍该种集群模式)。
RabbitMQ集群中的基本概念1)RabbitMQ的集群节点包括内存节点、磁盘节点。顾名思义内存节点就是将所有数据放在内存,磁盘节点将数据放在磁盘。不过,如前文所述,如果在投递消息时,打开了消息的持久化,那么即使是内存节点,数据还是安全的放在磁盘。
2)一个rabbitmq集 群中可以共享 user,vhost,queue,exchange等,所有的数据和状态都是必须在所有节点上复制的,一个例外是,那些当前只属于创建它的节点的消息队列,尽管它们可见且可被所有节点读取。rabbitmq节点可以动态的加入到集群中,一个节点它可以加入到集群中,也可以从集群环集群会进行一个基本的负载均衡。
RabbitMQ集群中有两种节点:1)Ram内存节点:只保存状态到内存(一个例外的情况是:持久的queue的持久内容将被保存到disk)
2)Disk磁盘节点:保存状态到内存和磁盘。
内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。RabbitMQ集群中,只需要一个磁盘节点来保存状态就足够了;如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。
RabbitMQ端口及用途
1)5672 客户端连接用途
2)15672 web管理接口
3)25672 集群通信用途
注意事项:RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。可以通过设置两个磁盘节点,至少有一个是可用的,可以保存元数据的更改。
RabbitMQ集群环境搭建
1.环境准备
网络条件良好的两台rabbitmq主机(可以参考CentOS7安装RabbitMQ),互相之间能够pin。
192.168.1.123
192.168.1.124
2.配置两台机器的/etc/hosts,添加如下内容
192.168.1.123 de9f15cd4e56
192.168.1.124 94c9a0ed1b55
3.修改两台机器的/var/lib/rabbitmq/.erlang.cookie内容一致,192.168.1.124机器的.erlang.cookie内容复制到124机器的.erlang.cookie文件,然后重启rabbitmq服务
4.配置集群,在192.168.1.123中执行如下命令
#仅关闭应用,节点不被关闭
rabbitmqctl stop_app
#将94c9a0ed1b55主机的rabbitmq实例加入集群中
rabbitmqctl join_cluster --ram rabbit@94c9a0ed1b55
rabbitmqctl start_app
#查看RabbitMQ集群情况
rabbitmqctl cluster_status
#修改RabbitMQ集群的名字为gymq,在那台机器上都可以
rabbitmqctl set_cluster_name gymq_cluster
如果集群搭建成功,Web控制台应该是这样子:
通过rabbitmqctl cluster_status查看
5.重启集群
#停止rabbitmq节点
rabbitmqctl stop
#后台运行rabbitmq
rabbitmq-server -detached
#看集群的运行状态变化
rabbitmqctl cluster_status
注意
当整个集群down掉时(比如挨个重启rabbitmq服务),最后一个down机的节点必须第一个启动到在线状态,如果不是这样,节点会等待30s等最后的磁盘节点恢复状态,然后失败。
如果最后下线的节点不能上线,可以通过forget_cluster_node 指令来踢出集群。
如果所有的节点不受控制的同时宕机,比如掉电,会进入所有的节点都会认为其他节点比自己宕机的要晚,即自己先宕机,这种情况下可以使用
force_boot指令来启动一个节点。
6.当一个节点不属于这个集群的时候,需要及时踢出,可以通过本地或者远程的方式
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
在我的192.168.1.124出现了错误:
Error: {resetting_only_disc_node,"You cannot reset a node when it is the only disc node in a cluster. Please convert another node of the cluster to a disc node first."}
(resetting_only_disc_node,“当节点是群集中唯一的光盘节点时,无法重置节点。请先将群集的另一个节点转换为光盘节点。”)
7.测试普通集群
在192.168.1.124上分别创建一个queue,exchange可以看到192.168.1.123上会将这些队列元数据同步过去
在192.168.1.124(192.168.1.124)上publish一条消息,消息也同步过去了
但是在192.168.1.124上执行如下命令模拟挂掉一个节点
rabbitmqctl stop_app
rabbitmqctl start_app
我尝试了下无论是在123或者124上publish消息,只要我让124节点重启,消息就丢失了,这种肯定满足不了日后需求
在stop_app或者stop掉broker之后在rabbitmq01节点的上队列已经不可用了,重启rabbitmq01的app或broker之后,虽然集群工作正常,但rabbitmq01上队列中消息会被清空(queue还是存在的)对于生产环境而已,这肯定是不可接受的,如果不能保证队列的高可用,那么做集群的意义也不太大了,还好rabbitmq支持Highly Available Queues,下面介绍下queue的HA。
8.配置镜像集群
默认情况下,RabbitMQ集群中的队列存在于集群中的单个节点上,这要看创建队列时声明在那个节点上创建,而exchange和binding则默认存在于集群中所有节点。队列可以通过镜像来提高可用性,HA依赖rabbitmq cluster,所以队列镜像也不适合WAN部署,每个被镜像的队列包含一个master和一个或者多个slave,当master因任何原因故障时,最老的slave被提升为新的master。发布到队列的消息被复制到所有的slave上,消费者无论连接那个node,都会连接到master;如果master确认要删除消息,那么所有slave就会删除队列中消息。队列镜像可以提供queue的高可用性,但不能分担负载,因为所有参加的节点都做所有的工作。
通过policy来配置镜像,策略可在任何时候创建,比如先创建一个非镜像的队列,然后在镜像,反之亦然。镜像队列和非镜像队列的区别是非镜像队列没有slaves,运行速度也比镜像队列快。设置策略,然后设置ha-mode,3种模式:all-所有(所有的queue),exctly-部分(需配置ha-params参数,此参数为int类型比如3,众多集群中的随机3台机器),nodes-指定(需配置ha-params参数,此参数为数组类型比如["3rabbit@F","rabbit@G"]这样指定为F与G这2台机器。比如通过如下两种方式
- 1.设置policy,以ha.开头的队列将会被镜像到集群其他所有节点,一个节点挂掉然后重启后需要手动同步队列消息
-
rabbitmqctl set_policy ha-all-queue "^ha\." '{"ha-mode":"all"}'
- 2.设置policy,以ha.开头的队列将会被镜像到集群其他所有节点,一个节点挂掉然后重启后会自动同步队列消息(生产环境采用这个方式)
-
rabbitmqctl set_policy ha-all-queue "^ha\." '{"ha-mode":"all","ha-sync-mode":"automatic"}'
更加具体的配置可以参考官网文档:https://www.rabbitmq.com/ha.html
问题:
配置镜像队列后,其中1台节点失败,队列内容是不会丢失,如果整个集群重启,队列中的消息内容仍然丢失,如何实现队列消息内容持久化那?
集群节点跑在disk模式,创建见消息的时候也声明了持久化,为什么还是不行那?
因为创建消息的时候需要指定消息是否持久化,如果启用了消息的持久化的话,重启集群消息也不会丢失了,前提是创建的队列也应该是创建的持久化队列。
9.客户端连接rabbitMQ集群的服务方式
1)客户端可以连接集群中的任意一个节点,如果一个节点故障,客户端自行重新连接到其他的可用节点;(不推荐,对客户端不透明)
2)通过动态DNS,较短的ttl
3)通过HA+4层负载均衡器(比如haproxy+keepalived)