MQ集群

目录

MQ集群

集群分类

普通集群

集群结构和特征

集群的部署

获取cookie

 准备集群配置

启动集群 

 镜像模式

镜像模式的特征

镜像模式的配置

 exactly模式

仲裁队列 

集群特征仲裁队列:仲裁队列是3.8版本以后才有的新功能,用来替代镜像队列,具备下列特征:

添加仲裁队列

 集群扩容

加入集群

 消息的幂等性


MQ集群

集群分类

RabbitMQ的是基于Erlang语言编写,而Erlang又是一个面向并发的语言,天然支持集群模式。RabbitMQ的集群有两种模式:

普通集群:是一种分布式集群,将队列分散到集群的各个节点,从而提高整个集群的并发能力。

镜像集群:是一种主从集群,普通集群的基础上,添加了主从备份功能,提高集群的数据可用性。

镜像集群虽然支持主从,但主从同步并不是强一致的,某些情况下可能有数据丢失的风险。因此在RabbitMQ的3.8版本以后,推出了新的功能:仲裁队列来代替镜像集群,底层采用Raft协议确保主从的数据一致性。

普通集群

集群结构和特征

普通集群,或者叫标准集群(classic cluster),具备下列特征:

  • 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息。
  • 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
  • 队列所在节点宕机,队列中的消息就会丢失

在这个集群中,在任意一个节点创建一个消息队列,集群中的任何一个节点都可以看到这个队列的消息,可以实现共享内容但是缺点是:实际的消息只存在创建这个队列的mq节点,加入这个mq节点宕机,那么消息队列的消息依旧会丢失 

 

集群的部署

我们先来看普通模式集群,我们的计划部署3节点的mq集群:

主机名控制台端口amqp通信端口
mq18081 ---> 156728071 ---> 5672
mq28082 ---> 156728072 ---> 5672
mq38083 ---> 156728073 ---> 5672

集群中的节点标示默认都是:rabbit@[hostname],因此以上三个节点的名称分别为:

  • rabbit@mq1
  • rabbit@mq2
  • rabbit@mq3

获取cookie

RabbitMQ底层依赖于Erlang,而Erlang虚拟机就是一个面向分布式的语言,默认就支持集群模式。集群模式中的每个RabbitMQ 节点使用 cookie 来确定它们是否被允许相互通信。

要使两个节点能够通信,它们必须具有相同的共享秘密,称为Erlang cookie。cookie 只是一串最多 255 个字符的字母数字字符。

每个集群节点必须具有相同的 cookie。实例之间也需要它来相互通信。

我们先在之前启动的mq容器中获取一个cookie值,作为集群的cookie。执行下面的命令:

docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie

 可以看到cookie值如下:

FXZMCVGLBIXZCDEMMVZQ

接下来,停止并删除当前的mq容器,我们重新搭建集群。

docker rm -f mq

 准备集群配置

在/tmp目录新建一个配置文件 rabbitmq.conf:

cd /tmp
# 创建文件
touch rabbitmq.conf

文件内容如下:

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

 再创建一个文件,记录cookie

cd /tmp
# 创建cookie文件
touch .erlang.cookie
# 写入cookie
echo "FXZMCVGLBIXZCDEMMVZQ" > .erlang.cookie
# 修改cookie文件的权限
chmod 600 .erlang.cookie

准备三个目录,mq1、mq2、mq3:

cd /tmp
# 创建目录
mkdir mq1 mq2 mq3

 然后拷贝rabbitmq.conf、cookie文件到mq1、mq2、mq3:

# 进入/tmp
cd /tmp
# 拷贝
cp rabbitmq.conf mq1
cp rabbitmq.conf mq2
cp rabbitmq.conf mq3
cp .erlang.cookie mq1
cp .erlang.cookie mq2
cp .erlang.cookie mq3

启动集群 

创建一个网络:

docker network create mq-net

运行命令

docker run -d --net mq-net \
-v ${PWD}/mq1/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=itcast \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq1 \
--hostname mq1 \
-p 8071:5672 \
-p 8081:15672 \
rabbitmq:3.8-management
docker run -d --net mq-net \
-v ${PWD}/mq2/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=itcast \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq2 \
--hostname mq2 \
-p 8072:5672 \
-p 8082:15672 \
rabbitmq:3.8-management
docker run -d --net mq-net \
-v ${PWD}/mq3/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \
-v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=itcast \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq3 \
--hostname mq3 \
-p 8073:5672 \
-p 8083:15672 \
rabbitmq:3.8-management

 镜像模式

在刚刚的案例中,一旦创建队列的主机宕机,队列就会不可用。不具备高可用能力。如果要解决这个问题,必须使用官方提供的镜像集群方案。

镜像模式的特征

默认情况下,队列只保存在创建该队列的节点上。而镜像模式下,创建队列的节点被称为该队列的主节点队列还会拷贝到集群中的其它节点,也叫做该队列的镜像节点。

但是,不同队列可以在集群中的任意节点上创建,因此不同队列的主节点可以不同。甚至,一个队列的主节点可能是另一个队列的镜像节点

用户发送给队列的一切请求,例如发送消息、消息回执默认都会在主节点完成,如果是从节点接收到请求,也会路由到主节点去完成。镜像节点仅仅起到备份数据作用

当主节点接收到消费者的ACK时,所有镜像都会删除节点中的数据。

总结如下:

  • 镜像队列结构是一主多从(从就是镜像)
  • 所有操作都是主节点完成,然后同步给镜像节点
  • 主宕机后,镜像节点会替代成新的主(如果在主从同步完成前,主就已经宕机,可能出现数据丢失)
  • 不具备负载均衡功能,因为所有操作都会有主节点完成(但是不同队列,其主节点可以不同,可以利用这个提高吞吐量)

这个镜像模式基于普通集群,增加了镜像节点当作备份 ,在一个主节点创建一个消息队列时,会在另一个节点创建这个消息队列的镜像,然后主节点会把这个消息队列的操作同步到镜像队列中。完成消息的同步。如果主节点宕机,拥有镜像队列的节点就会成为主节点,然后选择集群中的任一节点成为镜像。

这个模式的缺点就是:如果在消息还没完全同步时,主节点就宕机,也会造成消息的丢失

镜像模式的配置

镜像模式的配置有3种模式:

ha-modeha-params效果
准确模式exactly队列的副本量count集群中队列副本(主服务器和镜像服务器之和)的数量。count如果为1意味着单个副本:即队列主节点。count值为2表示2个副本:1个队列主和1个队列镜像。换句话说:count = 镜像数量 + 1。如果群集中的节点数少于count,则该队列将镜像到所有节点。如果有集群总数大于count+1,并且包含镜像的节点出现故障,则将在另一个节点上创建一个新的镜像。
all(none)队列在群集中的所有节点之间进行镜像。队列将镜像到任何新加入的节点。镜像到所有节点将对所有群集节点施加额外的压力,包括网络I / O,磁盘I / O和磁盘空间使用情况。推荐使用exactly,设置副本数为(N / 2 +1)。
nodesnode names指定队列创建到哪些节点,如果指定的节点全部不存在,则会出现异常。如果指定的节点在集群中存在,但是暂时不可用,会创建节点到当前客户端连接到的节点。
 exactly模式
rabbitmqctl set_policy ha-two "^two\." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
  • rabbitmqctl set_policy:固定写法
  • ha-two:策略名称,自定义
  • "^two\.":匹配队列的正则表达式,符合命名规则的队列才生效,这里是任何以two.开头的队列名称
  • '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}': 策略内容
    • "ha-mode":"exactly":策略模式,此处是exactly模式,指定副本数量
    • "ha-params":2:策略参数,这里是2,就是副本数量为2,1主1镜像
    • "ha-sync-mode":"automatic":同步策略,默认是manual,即新加入的镜像节点不会同步旧的消息。如果设置为automatic,则新加入的镜像节点会把主节点中所有消息都同步,会带来额外的网络开销

 

 

可以发现two.queue的主节点在mq1,然后有一个镜像队列(+1) 

仲裁队列 

集群特征仲裁队列:仲裁队列是3.8版本以后才有的新功能,用来替代镜像队列,具备下列特征:

  • 与镜像队列一样,都是主从模式,支持主从数据同步
  • 使用非常简单,没有复杂的配置
  • 主从同步基于Raft协议,强一致

添加仲裁队列

在任意控制台添加一个队列,一定要选择队列类型为Quorum类型。

 在任意控制台查看队列:

可以看到,仲裁队列的 + 2字样。代表这个队列有2个镜像节点。

因为仲裁队列默认的镜像数为5。如果你的集群有7个节点,那么镜像数肯定是5;而我们集群只有3个节点,因此镜像数量就是3.(包括主节点的消息队列)

 集群扩容

加入集群

1)启动一个新的MQ容器:

docker run -d --net mq-net \
-v ${PWD}/.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie \
-e RABBITMQ_DEFAULT_USER=itcast \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq4 \
--hostname mq5 \
-p 8074:15672 \
-p 8084:15672 \
rabbitmq:3.8-management

2)进入容器控制台:

docker exec -it mq4 bash

3)停止mq进程

rabbitmqctl stop_app

4)重置RabbitMQ中的数据:

rabbitmqctl reset

 5)加入mq1:

rabbitmqctl join_cluster rabbit@mq1

6)再次启动mq进程

rabbitmqctl start_app

 消息的幂等性

在消息的消费过程中可能因为网络的问题卡顿,让mq认为没有把消息消费成功然后又重复消费,导致一个消息被消费两次,这就是消息的幂等性

解决方法:

1.给每一个消息设置一个id,如果处理消息成功就把这个id存入redis,然后每次处理消息时,就把这个id去redis查询是否存在,如果存在就说明这个消息已经被消费

2.根据业务主键,根据消息来操作订单时,就去修改订单的状态,如果再来一个消息就先判断订单的状态来判断消息是否被消费

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/59462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UE5.2 C++ 实现拍照功能-带UI截图

整理了下,结合知乎上的一篇分享和自己的理解,最后总结出的一份带UI截图的代码,因为开发时间跨度有点大,中间有几天去玩游戏了,忘记之前参考的网页了,如果有知道的,欢迎留言补充。 头文件&#…

券商隔夜单自动下单交易接口

之前研究打板排板,研究怎么才能买得进去。 最近遇到几只利空跌停板,缩量跌停,明天大概率继续一字封板跌停。 如果卖不掉,意味着还要继续吃几个跌停,甚至ST票十几个跌停都有可能。 一次跌停亏几万,还是挺…

spi 回环

///tx 极性0 (sclk信号线空闲时为低电平) /// 相位0 (在sclk信号线第一个跳变沿进行采样) timescale 1ns / 1ps//两个从机 8d01 8d02 module top(input clk ,input rst_n,input [7:0] addr ,input …

基于物联网的温室大棚控制系统

本设计采用物联网方案,用STM32f103c8t6作为主控芯片,采用DHT11作为温湿度传感器,采集CO2使用JW01-CO2-V2.2传感器模块,并且通过BH1750传感器模块采集光照,通过土壤湿度传感器来获取大棚内部土壤湿度,ESP-01…

初级数据结构——栈

目录 前言一、栈的基本概念二、栈的实现方式三、栈的性能分析四、栈的应用场景五、栈的变体六、出栈入栈的动态图解七、代码模版八、总结结语 前言 数据结构栈(Stack)是一种线性的数据结构,它只允许在序列的一端(称为栈顶&#x…

信号-3-信号处理

main 信号捕捉的操作 sigaction struct sigaction OS不允许信号处理方法进行嵌套:某一个信号正在被处理时,OS会自动block改信号,之后会自动恢复 同理,sigaction.sa_mask 为捕捉指定信号后临时屏蔽的表 pending什么时候清零&…

OpenSSL 自签名

参考文档:unigui开发人员工作手册2021 参考文章:保姆级OpenSSL下载及安装教程-CSDN博客 下载 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 进入后向下拉找到下载位置,建议下载二进制版本的精简版&#xff0c…

Facebook 广告不展示的原因以及解决方法

很多小伙伴在进行Facebook广告投放时会遇到广告不展示的情况,那么遇到这种情况该怎么分析问题并解决呢?本文将为大家揭晓答案。 1. 主页错误或未发布 问题:主页可能存在错误或未正式发布。 解决方案:停用并重新激活主页。 访…

前端vue 列表中回显并下拉选择修改标签

1&#xff0c;vue数据列表中进行回显状态并可以在下拉框中选择修改&#xff0c;效果如下 2&#xff0c;vue 页面关键代码 <el-table-column label"审核" align"center" class-name"small-padding fixed-width" prop"status" >&…

安全见闻 -- 二进制与网络安全的关系

声明&#xff1a; 本文的学习内容来源于B站up主“泷羽sec”的公开分享&#xff0c;所有内容仅限于网络安全技术的交流学习&#xff0c;不涉及任何侵犯版权或其他侵权意图。如有任何侵权问题&#xff0c;请联系本人&#xff0c;我将立即删除相关内容。 本文旨在帮助网络安全爱好…

Spark 读取 HDFS 文件时 RDD 分区数的确定原理与源码分析

在 Spark 中&#xff0c;RDD 的分区数对于并行计算的效率非常重要&#xff0c;SparkCore 读取 HDFS 文件时 RDD 分区数的确定受多方面因素的影响。本文将从源码的角度分析 Spark 如何确定 RDD 分区数&#xff0c;并通过代码示例和案例帮助理解分区策略。 Spark RDD 分区数确定…

Python | Leetcode Python题解之第559题N叉树的最大深度

题目&#xff1a; 题解&#xff1a; class Solution:def maxDepth(self, root: Node) -> int:if root is None:return 0ans 0queue [root]while queue:queue [child for node in queue for child in node.children]ans 1return ans

Python 中.title()函数和.lower()函数

一.title()函数 1.title()函数的功能 将字符串中的每一单词的首字母大写 2.举例 S1"i love you" S2S1.title() print(S2)3.输出 二.lower()函数 1.lower()函数的功能 将字符串中的每一大写字母都变成的小写字母 2.举例 S1"I LOVE YOU" S2S1.lower()…

变更docker服务的存储路径

需求问题 docker服务默认存储路径是 /var/lib/docker 长时间写入文件的话有可能会写满磁盘。 1、停止容器服务&#xff0c;迁移数据 变更docker服务存储路径 在/etc/docker/daemon.json下加入配置文件即可&#xff0c;提前把/var/lib/docker下的文件全部都复制到新的存储目录…

STM32问题集

这里写目录标题 一、烧录1、 Can not connect to target!【ST-LINK烧录】 一、烧录 1、 Can not connect to target!【ST-LINK烧录】 烧录突然 If the target is in low power mode, please enable “Debug in Low Power mode” option from Target->settings menu 然后就&…

MySQL与Oracle对比及区别

一、比较 1、MySQL的特点 性能卓越&#xff0c;服务稳定&#xff0c;很少出现异常宕机&#xff1b; 开放源代码无版本制约&#xff0c;自主性及使用成本低&#xff1b; 历史悠久&#xff0c;社区和用户非常活跃&#xff0c;遇到问题及时寻求帮助&#xff1b; 软件体积小&#…

MySQL数据库:SQL语言入门 【2】(学习笔记)

目录 2&#xff0c;DML —— 数据操作语言&#xff08;Data Manipulation Language&#xff09; &#xff08;1&#xff09;insert 增加 数据 &#xff08;2&#xff09;delete 删除 数据 truncate 删除表和数据&#xff0c;再创建一个新表 &#xff08;3&#xf…

部署安装jdk8\redis\mysql8\nginx

安装jdk8 linux安装jdk8详细步骤_linux jdk8安装-CSDN博客 安装redis 安装redis 后台启动命令 cd /ra/redis-6.0.0/src ./redis-server --daemonize yes安装mysql8.0&#xff08;自定义目录安装&#xff09; 1、创建自己的mysql-8.0&#xff0c;解压mysql安装包 tar -zxv…

利用滑动窗口解题

目录 前言&#xff1a; 第一题&#xff1a;209. 长度最小的子数组 - 力扣&#xff08;LeetCode&#xff09; 第二题&#xff1a;1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; 第三题&#xff1a;3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&…

前端面试题整理-vue指令开发

1. 指令基础&#xff1a; 什么是 Vue 指令&#xff1f;Vue 中内置的指令有哪些&#xff1f;如何在 Vue 中创建自定义指令&#xff1f; Vue 中用于直接操作 DOM 的一种声明式方法&#xff0c;它们提供了一种简单而强大的方式来绑定 DOM 事件和属性。 v-bind (:) 用于动态绑定…