RabbitMQ 如何做分布式
前言
前面几篇文章介绍了消息队列中遇到的问题,这篇来聊聊 RabbitMQ 的集群搭建。
集群配置方案
RabbitMQ 中集群的部署方案有三种 cluster,federation,shovel。
cluster
cluster 有两种模式,分别是普通模式和镜像模式
cluster 的特点:
1、不支持跨网段,用于同一个网段内的局域网;
2、可以随意的动态增加或者减少;
3、节点之间需要运行相同版本的 RabbitMQ 和 Erlang 。
普通模式
cluster 普通模式(默认的集群模式),所有节点中的元数据是一致的,RabbitMQ 中的元数据会被复制到每一个节点上。
队列里面的数据只会存在创建它的节点上,其他节点除了存储元数据,还存储了指向 Queue 的主节点(owner node)的指针。
集群中节点之间没有主从节点之分。
举个栗子来说明下普通模式的消息传输:
假设我们 RabbitMQ 中有是三个节点,分别是 node1,node2,node3
。如果队列 queue1 的连接创建发生在 node1 中,那么该队列的元数据会被同步到所有的节点中,但是 queue1 中的消息,只会在 node1 中。
- 如果一个消费者通过 node2 连接,然后来消费 queue1 中的消息?
RabbitMQ 会临时在 node1、node2 间进行消息传输,因为非 owner 节点除了存储元数据,还会存储指向 Queue 的主节点(owner node)的指针。RabbitMQ 会根据这个指向,把 node1 中的消息实体取出并经过 node2 发送给 consumer 。
- 如果一个生产者通过 node2 连接,然后来向 queue1 中生产数据?
同理,RabbitMQ 会根据 node2 中的主节点(owner node)的指针,把消息转发送给 owner 节点 node1,最后插入的数据还是在 node1 中。
同时对于队列的创建,要平均的落在每个节点上,如果只在一个节点上创建队列,所有的消费,最终都会落到这个节点上,会产生瓶颈。
存在的问题:
如果 node1 节点故障了,那么 node2 节点无法取出 node1 中还未消费的消息实体。
1、如果做了队列的持久化,消息不会被丢失,等到 node1 恢复了,就能接着进行消费,但是在恢复之前其他节点不能创建 node1 中已将创建的队列。
2、如果没有做持久化,消息会丢失,但是 node1 中的队列,可以在其他节点重新创建,不用等待 node1 的恢复。
普通模式不支持消息在每个节点上的复制,当然 RabbitMQ 中也提供了支持复制的模式,就是镜像模式(参见下文)。
镜像模式
镜像队列会在节点中同步队列的数据,最终的队列数据会存在于每个节点中,而不像普通模式中只会存在于创建它的节点中。
优点很明显,当有主机宕机的时候,因为队列数据会同步到所有节点上,避免了普通模式中的单点故障。
缺点就是性能不好,集群内