RabbitMQ 普通集群
概述
1)普通模式中所有节点没有主从之分,所有节点的元数据(交换机、队列、绑定等)都是一致的.
例如只要有任意一个节点上面 新增交换机, 那么这个交换机的元数据也会被复制到其他节点上.
2)比较特殊的是队列,队列中的消息数据只保存在创建他的节点上,其他节点只保存元数据(队列名称、配置...)
和指针(指向创建该队列的节点)
.
例如 node1 创建 cyk.queue,那么 node2 只保存 队列的元数据 和 指向 node1 节点的指针,而 cyk.queue 中的消息,只会存在于 node1 节点中.
3)对于消息的传输如下:
假设有 node1、node2 节点,在 node1 中创建了 cyk.queue 队列.
- 此时有一个
生产者
和 node2 建立连接,向 cyk.queue 队列发送数据
:RabbitMQ 会根据 node2 中保存的 node1 的指针,把消息转发给 node1 节点,最后消息数据还是保存在 node1 中. - 此时有一个
消费者
和 node2 建立连接,从 cyk.queue 队列中消费
:RabbitMQ 会根据 node2 中保存的 node1 的指针,把消费消息的请求转发给 node1,然后 node1 将消息实体取出,并经过 node2 发送给 消费者.
4)存在的问题:
假设有 node1、node2 节点,在 node1 中创建了 cyk.queue 队列.
那么一旦 node1 宕机,那么 cyk.queue 中的消息也随之丢失,那么其他节点保存的 node1 指针也相当于失效,再想拿到消息,更是不可能了.
集群搭建
数据准备
1)先简单启动一个容器.
docker run -d --name mq \
--restart=always \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=1111 \
-p 15672:15672 \
-p 5672:5672 \
rabbitmq:3.8-management
2)RabbitMQ 底层基于 Erlang 语言,默认支持集群模式. 在集群模式中,每个 RabbitMQ 节点使用一个称为 Erlang cookie 的共享密钥来实现相互通信.
要想是两个节点能相互通信,必须具有相同的共享密钥(这个密钥是可以自定义的).
通过以下命令获取 cookie 值:
docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie
Ps:可以不需要这个步骤,因为只要保证每个节点中保存的 .erlang.cookie 值相同即可
3)在 ~/ 目录下创建 .erlang.cookie 文件,用来保存 Erlang Cookie(将来挂载数据)
touch ~/.erlang.cookie
echo "FQXBTQJMJLRUGFPIECYG" > ~/.erlang.cookie
chmod 600 ~/.erlang.cookie
4)在 ~/ 目录下创建 rabbitmq.conf 文件,配置 RabbitMQ 集群各种参数,以及节点信息和端口(包括禁止默认的 guest 用户,指定 AMQP 端口 5672)
loopback_users.guest = false
listeners.tcp.default = 5672
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit@mq1
cluster_formation.classic_config.nodes.2 = rabbit@mq2
cluster_formation.classic_config.nodes.3 = rabbit@mq3
5)在 ~/mq_cluster 目录下创建三个目录,用来存放不同节点信息.
mkdir -p ~/mq_cluster/mq1
mkdir -p ~/mq_cluster/mq2
mkdir -p ~/mq_cluster/mq3
6)将 ~/rabbitmq.conf 和 ~/.erlang.cookie 文件复制到三个节点目录中
cp ~/rabbitmq.conf ~/mq_cluster/mq1
cp ~/rabbitmq.conf ~/mq_cluster/mq2
cp ~/rabbitmq.conf ~/mq_cluster/mq3
cp ~/.erlang.cookie ~/mq_cluster/mq1
cp ~/.erlang.cookie ~/mq_cluster/mq2
cp ~/.erlang.cookie ~/mq_cluster/mq3
最后结构如下:
启动容器
1)创建网络,让集群中不同节点可以进行网络通信
docker network create mq-net
2)分别启动三个节点
docker run -d --net mq-net \
-v ~/mq_cluster/mq1/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ~/mq_cluster/mq1/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=1111 \
--name mq1 \
--hostname mq1 \
-p 5672:5672 \
-p 15672:15672 \
rabbitmq:3.8-management
docker run -d --net mq-net \
-v ~/mq_cluster/mq2/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ~/mq_cluster/mq2/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=1111 \
--name mq2 \
--hostname mq2 \
-p 5673:5672 \
-p 15673:15672 \
rabbitmq:3.8-management
docker run -d --net mq-net \
-v ~/mq_cluster/mq3/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ~/mq_cluster/mq3/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=1111 \
--name mq3 \
--hostname mq3 \
-p 5674:5672 \
-p 15674:15672 \
rabbitmq:3.8-management
3)打开 MQ 控制台,例如访问 mq1,就可以看到集群信息:
4)测试集群:
例如在 mq1 节点上添加 cyk.queue 的队列.
此时,访问 mq2 和 mq3 的控制台,也能看到这个队列.
至此集群搭建完成.
宕机情况
1)在 mq1 节点上创建一个 cyk.queue 队列,并发送一个消息,在其他节点上也可以看到同样效果.
2)此时,假设 mq1 节点宕机了(docker stop mq1),那么在 mq2 上可以看到在 mq1 上创建的 cyk.queue 队列的消息也随之丢失
3)mq1 节点宕机了,那么 mq2 节点也就无法取出 mq1 中未消费的消息实体.
- 如果 mq1 队列做了持久化,那么等到 node1 恢复了,就能进行消费. 但是在 mq1 恢复之前,其他节点不能创建 mq1 重点已创建的队列.
- 如果 mq1 队列没有持久化,消息也会丢失. 并且在 mq1 恢复之前,其他节点可以创建和 mq1 相同的队列.