RocketMQ详细介绍及核心问题解释(很全)

news2024/9/30 1:42:52

1. RocketMq是什么

一个纯Java、分布式队列模型的消息中间件,具有高可用、高可靠、高实时、低延迟的特点。(记住这句就行了)

2. RocketMq有什么功能

1、业务解耦:这也是发布订阅的消息模型。生产者发送指令到MQ中,然后下游订阅这类指令的 消费者会收到这个指令执行相应的逻辑,整个过程与具体业务无关,抽象成了一个发送指令,存储指令,消费指令的过程。

2、前端削峰:前端发起的请求在短时间内太多后端无法处理,可以堆积在MQ中,后端按照一定的顺序处理,秒杀系统就是这么实现的。

3、亿级消息的堆积能力,单个队列中的百万级消息的累积容量。

4、高可用性:Broker服务器支持多Master多Slave的同步双写以及Master多Slave的异步复制模式,其中同步双写可保证消息不丢失。

5、高可靠性:生产者将消息发送到Broker端有三种方式,同步、异步和单向,其中同步和异步都可以保证消息成功的成功发送。Broker在对于消息刷盘有两种策略:同步刷盘和异步刷盘,其中同步刷盘可以保证消息成功的存储到磁盘中。消费者的消费模式也有集群消费和广播消费两种,默认集群消费,如果集群模式中消费者挂了,一个组里的其他消费者会接替其消费。综上所述,是高可靠的。

6、支持分布式事务消息:这里是采用半消息确认和消息回查机制来保证分布式事务消息的,下面会详细描述。

7、支持消息过滤:建议采用消费者业务端的tag过滤。

8、支持顺序消息:消息在Broker中是采用队列的FIFO模式存储的,也就是发送是顺序的,只要保证消费的顺序性即可。

9、支持定时消息和延迟消息:Broker中由定时消息的机制,消息发送到Broker中,不会立即被Consumer消费,会等到一定的时间才被消费。延迟消息也是一样,延迟一定时间之后才会被Consumer消费。

3. RocketMq的架构

在这里插入图片描述

RocketMq一共有四个部分组成:NameServer,Broker,Producer生产者,Consumer消费者,每一部分都是集群部署的。

NameServer

NameServer是一个无状态的服务器,角色类似于Dubbo的Zookeeper,但比Zookeeper更轻量。特点:

  • 每个NameServer结点之间是相互独立,彼此没有任何信息交互。

  • Nameserver被设计成几乎是无状态的,通过部署多个结点来标识自己是一个伪集群,Producer在发送消息前从NameServer中获取Topic的路由信息也就是发往哪个Broker,Consumer也会定时从NameServer获取topic的路由信息,Broker在启动时会向NameServer注册,并定时进行心跳连接,且定时同步维护的Topic到NameServer。

    功能主要有两个:

    • 1、跟Broker结点保持长连接。

    • 2、维护Topic的路由信息。

Broker

消息存储和中转角色,负责存储和转发消息。

  • Broker内部维护着一个个Message Queue,用来存储消息的索引,真正存储消息的地方是CommitLog(日志文件)。
  • 单个Broker与所有的Nameserver保持着长连接和心跳,并会定时将Topic信息同步到NameServer,和NameServer的通信底层是通过Netty实现的。

Producer

消息生产者,业务端负责发送消息,由用户自行实现和分布式部署。

Producer的负载均衡

Producer的负载均衡是由MQFaultStratege.selectOneMessageQueue()来实现的。这个方法就是随机选择一个要发送消息的broker来达到负载均衡的效果,选择的标准:尽量不选刚刚选过的broker,尽量不选发送上条消息延迟过高或没有响应的broker,也就是找到一个可用的broker。

发送的三种策略

Producer发送消息有三种方式:同步、异步和单向

同步:同步发送是指发送方发出数据后等待接收方发回响应后在发送下一个数据包。一般用于重要的消息通知,如重要的通知邮件或者营销短信等。

异步:异步发送是指发送方发出数据后不等接收方发回响应就发出下一个数据包。一般用于可能链路耗时较长而对响应时间比较敏感的场景。如视频上传后通知启动转码服务。

单向:单向发送是指只负责发送消息而不等待接收方发送响应且没有回调函数,适合那些耗时比较短且对可靠性要求不高的场景,例如日志收集。

Consumer

消息消费者,负责消费消息,由用户自行实现并进行集群部署。

推拉消费模式

PULL:拉取型消费者主动从broker中拉取消息消费,只要拉取到消息,就会启动消费过程,称为主动型消费。

PUSH:推送型消费者就是要注册消息的监听器,监听器是要用户自行实现的。当消息达到broker服务器后,会触发监听器拉取消息,然后启动消费过程。但是从实际上看还是从broker中拉取消息,称为被动消费型。

集群还是广播

看业务需求,默认是集群消费。

集群消费:broker中的一条消息会发送给订阅这个topic的一个消费组里的唯一一个消费者进行消费。如果这个消费者挂掉了,组里的其他消费者会接替它进行消费。

广播消费:broker中的一条消息会发送给订阅这个topic的一个消费组里的每一个消费者进行消费。

Consumer的负载均衡

Consumer的负载均衡是指将MessageQueue中的消息队列分配到消费者组里的具体消费者。

Consumer在启动的时候会实例化rebalanceImpl,这个类负责消费端的负载均衡。通过rebalanceImpl调用allocateMesasgeQueueStratage.allocate()完成负载均衡。

每次有新的消费者加入到组中就会重新做一下分配。每10秒自动做一次负载均衡。

4. RocketMq消息模型(专业术语)

Message

就是要传输的消息,一个消息必须有一个主题,一条消息也可以有一个可选的Tag(标签)和额外的键值对,可以用来设置一个业务的key,便于开发中在broker服务端查找消息。

Topic

主题,是消息的第一级类型,每条消息都有一个主题,就像信件邮寄的地址一样。主题就是我们具体的业务,比如一个电商系统可以有订单消息,商品消息,采购消息,交易消息等。Topic和生产者和消费者的关系非常松散,生产者和Topic可以是1对多,多对1或者多对多,消费者也是这样。

Tag

标签,是消息的第二级类型,可以作为某一类业务下面的二级业务区分,它的主要用途是在消费端的消息过滤。比如采购消息分为采购创建消息,采购审核消息,采购推送消息,采购入库消息,采购作废消息等,这些消息是同一Topic和不同的Tag,当消费端只需要采购入库消息时就可以用Tag来实现过滤,不是采购入库消息的tag就不处理。

Group

组,可分为ProducerGroup生产者组合ConsumerGroup消费者组,一个组可以订阅多个Topic。一般来说,某一类相同业务的生产者和消费者放在一个组里。

Message Queue

消息队列,一个Topic可以划分成多个消息队列。Topic只是个逻辑上的概念,消息队列是消息的物理管理单位,当发送消息的时候,Broker会轮询包含该Topic的所有消息队列,然后将消息发出去。有了消息队列,可以使得消息的存储可以分布式集群化,具有了水平的扩展能力。

offset

是指消息队列中的offset,可以认为就是下标,消息队列可看做数组。offset是java long型,64位,理论上100年不会溢出,所以可以认为消息队列是一个长度无限的数据结构。

5. 核心问题

5.1 如何保证顺序消息?

顺序由producer发送到broker的消息队列是满足FIFO的,所以发送是顺序的,单个queue里的消息是顺序的。多个Queue同时消费是无法绝对保证消息的有序性的。所以,同一个topic,同一个queue,发消息的时候一个线程发送消息,消费的时候一个线程去消费一个queue里的消息。

5.2 怎么保证消息发到同一个queue里?

RocketMQ给我们提供了MessageQueueSelector接口,可以重写里面的接口,实现自己的算法,比如判断i%2==0,那就发送消息到queue1否则发送到queue2。

5.3 如何实现消息过滤?

有两种方案,一种是在broker端按照Consumer的去重逻辑进行过滤,这样做的好处是避免了无用的消息传输到Consumer端,缺点是加重了Broker的负担,实现起来相对复杂。另一种是在Consumer端过滤,比如按照消息设置的tag去重,这样的好处是实现起来简单,缺点是有大量无用的消息到达了Consumer端只能丢弃不处理。

5.4 如果由于网络等原因,多条重复消息投递到了Consumer端,你怎么进行消息去重?

这个得先说下消息的幂等性原则:就是用户对于同一种操作发起的多次请求的结果是一样的,不会因为操作了多次就产生不一样的结果。只要保持幂等性,不管来多少条消息,最后处理结果都一样,需要Consumer端自行实现。

去重的方案:因为每个消息都有一个MessageId, 保证每个消息都有一个唯一键,可以是数据库的主键或者唯一约束,也可以是Redis缓存中的键,当消费一条消息前,先检查数据库或缓存中是否存在这个唯一键,如果存在就不再处理这条消息,如果消费成功,要保证这个唯一键插入到去重表中。

5.5 RocketMQ是怎么实现分布式事务消息的?

半消息:是指暂时还不能被Consumer消费的消息,Producer成功发送到broker端的消息,但是此消息被标记为“暂不可投递”状态,只有等Producer端执行完本地事务后经过二次确认了之后,Consumer才能消费此条消息。

在这里插入图片描述

上图就是分布式事务消息的实现过程,依赖半消息,二次确认以及消息回查机制。

1、Producer向broker发送半消息

2、Producer端收到响应,消息发送成功,此时消息是半消息,标记为“不可投递”状态,Consumer消费不了。

3、Producer端执行本地事务。

4、正常情况本地事务执行完成,Producer向Broker发送Commit/Rollback,如果是Commit,Broker端将半消息标记为正常消息,Consumer可以消费,如果是Rollback,Broker丢弃此消息。

5、异常情况,Broker端迟迟等不到二次确认。在一定时间后,会查询所有的半消息,然后到Producer端查询半消息的执行情况。

6、Producer端查询本地事务的状态

7、根据事务的状态提交commit/rollback到broker端。(5,6,7是消息回查)

5.6 RocketMQ如何能保证消息的可用性/可靠性?

要从Producer,Consumer和Broker三个方面来回答。

从Producer角度分析,如何确保消息成功发送到了Broker?

1、可以采用同步发送,即发送一条数据等到接受者返回响应之后再发送下一个数据包。如果返回响应OK,表示消息成功发送到了broker,状态超时或者失败都会触发二次重试。

2、可以采用分布式事务消息的投递方式。

3、如果一条消息发送之后超时,也可以通过查询日志的API,来检查是否在Broker存储成功。总的来说,Producer还是采用同步发送来保证的。

从Broker角度分析,如何确保消息持久化?

1、消息只要持久化到CommitLog(日志文件)中,即使Broker宕机,未消费的消息也能重新恢复再消费。

2、Broker的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在pagecache中(内存中),但是同步刷盘更可靠,它是Producer发送消息后等数据持久化到磁盘之后再返回响应给Producer。

3、Broker支持多Master多Slave同步双写和多Master多Slave异步复制模式,消息都是发送给Master主机,但是消费既可以从Master消费,也可以从Slave消费。同步双写模式可以保证即使Master宕机,消息肯定在Slave中有备份,保证了消息不会丢失。

从Consumer角度分析,如何保证消息被成功消费?

Consumer自身维护了个持久化的offset(对应Message Queue里的min offset),用来标记已经成功消费且已经成功发回Broker的消息下标。如果Consumer消费失败,它会向Broker发回消费失败的状态,发回成功才会更新自己的offset。如果发回给broker时broker挂掉了,Consumer会定时重试,如果Consumer和Broker一起挂掉了,消息还在Broker端存储着,Consumer端的offset也是持久化的,重启之后继续拉取offset之前的消息进行消费。

5.7 刷盘实现

RocketMQ提供了两种刷盘策略:同步刷盘和异步刷盘

同步刷盘:在消息达到Broker的内存之后,必须刷到commitLog日志文件中才算成功,然后返回Producer数据已经发送成功。

异步刷盘:异步刷盘是指消息达到Broker内存后就返回Producer数据已经发送成功,会唤醒一个线程去将数据持久化到CommitLog日志文件中。

优缺点分析:同步刷盘保证了消息不丢失,但是响应时间相对异步刷盘要多出10%左右,适用于对消息可靠性要求比较高的场景。异步刷盘的吞吐量比较高,RT小,但是如果broker断电了内存中的部分数据会丢失,适用于对吞吐量要求比较高的场景。

5.8 说下RocketMQ的负载均衡是如何实现的?

RocketMQ是分布式消息服务,负载均衡时再生产和消费的客户端完成的。

在这里插入图片描述

上面讲过,nameServer保存着Topic的路由信息,路由记录了broker集群节点的通讯地址,broker的名称以及读写队列数量等信息。写队列writeQueue表示生产者可以写入的队列数,如果不做配置默认为4,也就是queueId是0,1,2,3,broker收到消息后根据queueId生成消息队列,生产者负载均衡的过程的实质就是选择broker集群和queueId的过程。读队列readQueue表示broker中可以供消费者读取信息的队列个数,默认也是4个,也就是queueId也是0,1,2,3。消费者拿到路由信息后会选择queueId,从对应的broker中读取数据消费。

下面我从生产者负载均衡和消费者负载均衡两个角度来说明:

生产者的负载均衡:实质是在选择MessageQueue对象(内部包含了brokerName和queueId),第一种是默认策略,从MessageQueue列表中随机选择一个,算法时通过自增随机数对列表打下取余得到位置信息,但获得的MessageQueue所在集群不能是上次失败集群。第二种是超时容忍策略,先随机选择一个MessageQueue,如果因为超时等异常发送失败,会优先选择该broker集群下其他MessageQueue发送,如果没找到就从之前发送失败的Broker集群中选一个进行发送,若还没有找到才使用默认策略。

消费者的负载均衡:这里可选的有六种算法。

  • 平均分配算法

    在这里插入图片描述

  • 环形算法

    在这里插入图片描述

在这里插入图片描述

  • 指定机房算法

  • 就近机房算法

  • 统一哈希算法

    使用一致性哈希算法进行负载,每次负载都会重建一致性hash路由表,获取本地客户端负责的所有队
    列信息。默认的hash算法为MD5,假设有4个消费者客户端和2个消息队列mq1和mq2,通过hash后分
    布在hash环的不同位置,按照一致性hash的顺时针查找原则,mq1被client2消费,mq2被client3消
    费。

  • 手动配置算法

    在这里插入图片描述

  • 指定机房算法

  • 就近机房算法

  • 统一哈希算法

    使用一致性哈希算法进行负载,每次负载都会重建一致性hash路由表,获取本地客户端负责的所有队
    列信息。默认的hash算法为MD5,假设有4个消费者客户端和2个消息队列mq1和mq2,通过hash后分
    布在hash环的不同位置,按照一致性hash的顺时针查找原则,mq1被client2消费,mq2被client3消
    费。

  • 手动配置算法

    [外链图片转存中…(img-KT99x3si-1704553913083)]

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

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

相关文章

pytorch06:权重初始化

目录 一、梯度消失和梯度爆炸1.1相关概念1.2 代码实现1.3 实验结果1.4 方差计算1.5 标准差计算1.6 控制网络层输出标准差为11.7 带有激活函数的权重初始化 二、Xavier方法与Kaiming方法2.1 Xavier初始化2.2 Kaiming初始化2.3 常见的初始化方法 三、nn.init.calculate_gain 一、…

多线程高级知识点

多线程高级知识点 1.ThreadLocal 1.1 什么是 ThreadLocal? ​ ThreadLocal 叫做本地线程变量,意思是说,ThreadLocal 中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal 为变量在每个线程…

高性能NVMe Host Controller IP

NVMe Host Controller IP 介绍 NVMe Host Controller IP可以连接高速存储PCIe SSD,无需CPU和外部存储器,自动加速处理所有的NVMe协议命令,具备独立的数据写入AXI4-Stream/FIFO接口和数据读取AXI4-Stream/FIFO接口,非常适合于超高…

插槽slot涉及到的样式污染问题

1. 前言 本次我们主要结合一些案例研究一下vue的插槽中样式污染问题。在这篇文章中&#xff0c;我们主要关注以下两点: 父组件的样式是否会影响子组件的样式&#xff1f;子组件的样式是否会影响父组件定义的插槽部分的样式&#xff1f; 2. 准备代码 2.1 父组件代码 <te…

mysql基础-数据操作之增删改

目录 1.新增数据 1.1单条数据新增 1.2多条数据新增 1.3查询数据新增 2.更新 2.1单值更新 2.2多值更新 2.3批量更新 2.3.1 批量-单条件更新 2.3.2批量-多条件更新 2.4 插入或更新 2.5 联表更新 3.删除 本次分享一下数据库的DML操作语言。 操作表的数据结构&#xf…

《计算机科学中的建模技术》复习点

0 考试题型 题型&#xff1a;选择、填空、大题&#xff08;综合题&#xff09; 分值&#xff1a;选择填空30分&#xff0c;综合70分 填空&#xff1a;基本概念题 第 1 章&#xff1a;计算机科学基本问题与数学建模概要 1.1 科学计算的基本概念 科学计算是指利用计算机来完成…

Transformer架构和对照代码详解

1、英文架构图 下面图中展示了Transformer的英文架构&#xff0c;英文架构中的模块名称和具体代码一一对应&#xff0c;方便大家对照代码、理解和使用。 2、编码器 2.1 编码器介绍 从宏观⻆度来看&#xff0c;Transformer的编码器是由多个相同的层叠加⽽ 成的&#xff0c;每个…

【数据结构】二叉树的概念及堆

前言 我们已经学过了顺序表、链表、栈和队列这些属于线性结构的数据结构&#xff0c;那么下面我们就要学习我们第一个非线性结构&#xff0c;非线性结构又有哪些值得我们使用的呢&#xff1f;那么接下来我们就将谈谈树的概念了。 1.树的概念与结构 1.1树的概念 树是一种非线性…

2.C++的编译:命令行、makefile和CMake

1. 命令行编译 命令行编译是指直接在命令行中输入以下指令&#xff1a; 预处理&#xff1a;gcc -E main.c -o main.i 编译&#xff1a;gcc -S main.i -o main.s 汇编&#xff1a;gcc -c main.s -o main.o 链接&#xff1a;gcc main.o -o main 命令汇总&#xff1a;gcc main.c …

【ZooKeeper高手实战】ZAB协议:ZooKeeper分布式一致性的基石

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

第17课 为rtsp流加入移动检测功能

在上节课&#xff0c;我们成功拿到了rtsp视频和音频流&#xff0c;在第13课&#xff0c;我们为普通的usb摄像头加上了移动检测功能&#xff0c;那能不能给rtsp摄像头也加上移动检测功能以实现一些好玩的应用呢&#xff1f;答案是肯定的&#xff0c;在usb摄像头检测中&#xff0…

BetaFlight开源代码之电压校准

BetaFlight开源代码之电压校准 1. 源由2. 分析数据流3. 采样电路3. 原理4. 示例5. 实测&转换数据6. 参考资料 1. 源由 既然复杂的BetaFlight开源代码之电流校准都过了一遍&#xff0c;电压相对来说是比较简单的&#xff0c;一起过一下 2. 分析数据流 电源路径1》采样电路…

【Spring实战】24 使用 Spring Boot Admin 管理和监控应用

文章目录 1. 定义2. 使用场景3. 主要功能4. 示例1&#xff09;[服务端] 添加依赖2&#xff09;[服务端] 相关配置3&#xff09;[服务端] 启动类4&#xff09;[服务端] 启动服务5&#xff09;[服务端] 浏览器访问6&#xff09;[客户端] 添加依赖7&#xff09;[客户端] 相关配置8…

双变量probit模型

1. Probit模型 1.1 模型含义 假设个体只有两种选择&#xff0c;y1或y0。影响选择的变量都包括在向量x中。即线性概率模型为 y值服从两点分布 被认为是连接函数&#xff0c;函数选择具有一定的灵活性。如果为标准正态的累积分布函数&#xff0c;则模型成为Probit模型&#xff…

网络嗅探器的设计与实现(2024)-转载

1.题目描述 参照 raw socket 编程例子&#xff0c;设计一个可以监视网络的状态、数据流动情况以及网络上传输 的信息的网络嗅探器。 2.运行结果 3.导入程序需要的库 请参考下面链接: 导入WinPcap到Clion (2024)-CSDN博客 4.参考代码 #define HAVE_REMOTE #define LINE_LEN …

【数据库原理】(11)SQL数据查询功能

基本格式 SELECT [ALL|DISTINCT]<目标列表达式>[,目标列表达式>]... FROM <表名或视图名>[,<表名或视图名>] ... [ WHERE <条件表达式>] [GROUP BY<列名 1>[HAVING <条件表达式>]] [ORDER BY <列名 2>[ASC DESC]];SELECT: 指定要…

WinForms中的UI卡死

WinForms中的UI卡死 WinForms中的UI卡死通常是由于长时间运行的操作阻塞了UI线程所导致的。在UI线程上执行的操作&#xff0c;例如数据访问、计算、文件读写等&#xff0c;如果耗时较长&#xff0c;会使得UI界面失去响应&#xff0c;甚至出现卡死的情况。 解决方法 为了避免…

061:vue中通过map修改一维数组,增加一些变量

第061个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

系列二、GitHub中的Alpha、Beta、RC、GA、Release等各个版本

一、GitHub中的Alpha、Beta、RC、GA 1.1、概述 1.2、参考 https://www.cnblogs.com/huzhengyu/p/13905129.html

Qt——TCP UDP网络编程

目录 前言正文一、TCP二、UDP1、基本流程2、必备知识 三、代码层级1、UDP服务端 END、总结的知识与问题1、如何获取QByteArray中某一字节的数据&#xff0c;并将其转为十进制&#xff1f;2、如何以本年本月本日为基础&#xff0c;获取时间戳&#xff0c;而不以1970为基础&#…