参考资料:
https://www.cnblogs.com/xishuai/p/rabbitmq-cluster.html
http://www.ywnds.com/?p=4741
https://blog.csdn.net/zhu_tianwei/article/details/40930305
对异常情况解释的比较多
为什么需要集群
- 摆脱单机资源上的限制,提供更大的吞吐量
- 提供更加稳定的更高可用的服务
集群中节点之间需要同步的信息rabbitmq的元数据
a. 队列元数据:队列名称和它的属性;
b. 交换器元数据:交换器名称、类型和属性;
c. 绑定元数据:一张简单的表格展示了如何将消息路由到队列;
d. vhost元数据:为vhost内的队列、交换器和绑定提供命名空间和安全属性;
e. 元数据信息需要保存的磁盘中,所以每个集群中至少需要一个disk节点
因此,当用户访问其中任何一个RabbitMQ节点时,通过rabbitmqctl查询到的queue/user/exchange/vhost等信息都是相同的。
rabbitmq 的集群模式
集群内节点的类型
磁盘节点
保存数据到磁盘和内存中,如果集群中群都是内存节点,那就不能停止他们,否则元数据就会丢。
RabbitMQ只要求集群中至少有一个磁盘节点,如果只有一个磁盘节点,刚好又崩溃了,集群可以继续路由消息,但不能创建队列、交换器、绑定、添加用户、更改权限等操作。所以,
建议设置两个磁盘节点
,当内存节点重启后,会连接到预先配置的磁盘节点,下载当前集群元数据拷贝,所以要将所有磁盘节点告诉内存节点。
内存节点
数据只保存到内存中,除非遇到
- publish消息的时候指定需要持久化
- 内存吃紧的时候,会把部分消息持久化到磁盘
内存节点的特点就是执行效率高
普通模式
不是每个节点都有所有队列的完全拷贝,如果在集群中创建队列,只会在单个节点上创建完整的队列信息(元数据、状态、内容),所有其他节点只知道队列的元数据和指向该队列的节点指针。
既然一个队列的数据只存在一个节点上,那么在连接集群内其他节点的时候,是如何进行发布消息和消费消息的呢?
如果消息生产者所连接的是节点2或者节点3,此时队列1的完整数据不在该两个节点上,那么在发送消息过程中这两个节点主要起了一个路由转发作用,根据这两个节点上的元数据(也就是上文提到的:指向queue的owner node的指针)转发至节点1上,最终发送的消息还是会存储至节点1的队列1上。
同样,如果消息消费者所连接的节点2或者节点3,那这两个节点也会作为路由节点起到转发作用,将会从节点1的队列1中拉取消息进行消费。
如果节点崩溃了,附加在队列上的消费者也就无法接收新的消息了。可以让消费者重连到集群并重新创建队列,这种做法仅当队列没设置持久化时才可行,如果做了队列持久化或消息持久化,必须等到对应的节点恢复了才能被消费
,这是为了确保当失败的节点恢复后加入集群,节点上的队列消息不会丢失。
为什么不将队列内容和状态复制到所有节点:
- 存储空间,如果每个集群节点都拥有所有队列的完全拷贝,添加新节点不会带来更多存储空间;
- 性能,消息的发布者需要将消息复制到每一个集群节点,对于持久化消息,网络和磁盘复制都会增加。
优点:
- 使用集群能很好的实现服务能力的水平拓展
缺点:
- 因为单个队列只维持在单个节点上,也很难认为是高可用
- 如果是不持久化的消息和队列,单机宕机后消息会丢失
镜像模式 把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案
根据策略可以为节点定义镜像节点,镜像节点之间可以实现队列中消息实体的同步。
对于发送方确认消息,Rabbit会在所有队列和队列的从拷贝安全地接收到消息时,才会通知发送方。
优点:
- 因为能对节点维护的队列中的消息实体做了同步,可以保证
缺点:
- 因为要进行消息实体的复制,所以势必会影响系统的性能
- 网络通信也会加大,如果消息量比较大话