rocketmq-基础概念

一、MQ概述

1、简介

MQ,是一种提供消费队列服务的中间件,是一套提供了消息生产、存储消费全过程API的系统。

2、MQ用途

限流削峰

MQ可以将系统的超量请求暂存其中,以便系统后期可以慢慢进行处理,从而避免请求的丢失或系统被压垮

异步解耦

上游系统对下游系统的调用,则会大大降低系统的吞吐量与并发度,且系统耦合度太高。

而异步调用则会解决这些问题。因此两层之间若要实现由同步转异步的话,一般做法是,在两层之间加一层MQ层。

数据收集

分布式系统会产生海量级数据流,如:业务日志,监控数据,用户行为等。针对这些数据进行实时或批量汇总,然后对这些数据流进行大数据分析,可以通过MQ数据收集是最好的选择。

3、RocketMQ

RocketMQ是使用Java语言开发的MQ产品。经过数年阿里双11的考验,性能与稳定性非常高。其没有遵循任何常见的MQ协议,而是使用自研协议。

二、RocketMQ概述

1、简介

RocketMQ是一个统一消息引擎、轻量级数据处理平台。

RocketMQ是一款阿里巴巴开源的消息中间件。

官网:http://rocketmq.apache.org

2、基本概念

1、消息(message)

消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题(topic)。

2、主题(topic)

topic表示一类消息的集合,每个主题包含若干条消息,每条消息属于一个主题,是RocketMQ进行消息订阅的基本单位。

3、标签(tag)

用于同一个主题下区分不同类型的消息。来自同一业务单元的消息,可以根据业务的不同设置不同的标签。相当于对主题进行再次分类。

4、队列

存储消息的物理实体,一个Topic中可以包含多个Queue,每个Queue中存放的就是该Topic的消息。

一个Topic的Queue中的消息只能被一个消费组中的消费者消费。一个Queue中的消息不允许同一个消费者组的多个消费者同时消费。

在学习的参考资料中,还会看到一个概念,分片(Sharding)。在RocketMQ中,分片指的是存放相应的Topic的Broker。每个分片中会创建出相应数量的分区,即Queue。

如下图,一个分片在不同的Broker中,每个Broker的分片存在一个Topic,每个分片的Topic的Queue的数量不同,但Queue的大小相同。

5、消息标识(MessageId/Key)

RocketMQ中每个消息的唯一标识,且可以携带具有业务标识的Key,以便消息查询。

需要注意的是,MessageId有两个:在生产者send()消息时会自动生成一个MessageId(msgId),

当消息到达broker后,broker也会生成一个MessageId(offsetMsgId),msgId、offsetMsgId与key

都称为消息标识

  • msgId:由生产者端生成,其生成规则:

       producerIp + 进程pid + MessageClientIdSetter类的ClassLoader的hashCode + 当前时间 + AutomicInteger自增计数器

  • offsetMsgId:由Broker端生成,其生成规则:

       brokerIp + 物理分区的offset(Queue中的偏移量)

  • key:由用户指定的业务相关唯一标识

三、RocketMQ架构

1、生产者

生产者负责生产消息。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。

RocketMQ中的消息生产者都是以生产者组(Producer Group)的形势出现。生产者组是同一类生产者的集合这类生产者发送相同Topic类型的消息

一个生产者组可以发送多个Topic的消息

2、消费者

1)、消费者负责消费消息。Consumer会从Broker服务器中获取消息,并且对消息进行相关业务处理。

2)、RocketMQ中的消费者都是以消费者组的形势出现的。Consumer Group是同一类Consumer的集合,这类Consumer消费同一个Topic类型的消息。

3)、Consumer Group在消费方面实现了Loader Balance(将一个Topic的不同Queue平均分配给同一个Consumer Group的不同的Consumer)

容错(一个Consumer挂了,该Consumer Group的其他Consumer可以接着消费原Consumer消费的Queue)的目标变得非常容易。

4)、消费者组的Consumer的数量应该 <= 订阅的Queue的数量。如果超出Queue的数量,那么多出来的Consumer将不能消费消息

不过,一个Topic类型的消息可以被多个消费者组同时消费。

注意:第3点是消费者的核心。

3、NameServer

1、功能介绍

NameServer是一个Broker与Topic路由的注册中心,支持Broker的动态注册与发现。

以前的RocketMQ的注册中心依赖于Zookeeper,后来采用自己内部的NameServer来替代Zookeeper。

主要包括2个功能:

  • Broker管理:接收Broker集群的注册信息并保存下来做为路由信息的基本数据;提供心跳检测机制,检查Broker是否存活。
  • 路由信息管理:每个NameServer中都保存着Broker集群的整个路由信息用于客户端查询的队列信息。Producer和Consumer通过NameServer可以获取整个Broker集群的路由信息,从而进行消息的投递和消费。

2、路由注册

1、NameServer通常也是集群部署,不过NameServer是无状态的,即NameServer集群中的各个节点之间是无差异的,各个节点相互不进行通讯

2、那各个节点中的数据是怎么进行数据同步的?

在Broker节点启动时,轮询NameServer列表,与每个NameServer节点建立长连接,发起注册请求。中NameServer内部维护一个Broker列表,用来动态存储Broker信息。

3、Broker节点为了证明自己活着,会与NameServer维护长连接,将最新的信息以心跳包的方式上报给NameServer,每30秒发送一次心跳。心跳包:BrokerId、Broker地址、Broker名、Broker所属集群名。NameServer接收到心跳包后,更新心跳时间戳,记录这个Broker的存活时间。

3、路由剔除

由于Broker宕机、关机或网络抖动等原因,NameServer没有接收到Broker心跳,NameServer可能会将其Broker从列表中剔除。

NameServer中有一个定时任务,每隔10秒就会扫描一次Broker表,查看每个Broker的最新心跳时间戳距离当前时间是否超过120秒,

如果超过,则判定Broker失效,然后将其从Broker列表中剔除。

时间戳 - currentTime > 120,剔除其Broker。 

4、路由发现

RocketMQ的路由发现采用的是Pull模型,当Topic路由信息发生变化时,NameServer不会主动推送给客户端,而是客户端定时Pull Topic最新路由。

默认客户端每30秒会Pull一次最新路由。

Client—30s—>拉取主题的最新路由;

扩展:

1)Push模型:推送模型。实时性较好,是一个发布-订阅模型,需要维护一个长连接。

  适用场景:

    实时性要求高;

    Client数量不多,Server数据变化频繁;

2)Pull模型:拉取模型。实时性比较差。

3)Long Polling模型:长轮询模型。是对Push与Pull的整合,充分利用了这两种模型的优势,屏蔽了它们的劣势。

5、客户端与NameServer 连接策略

客户端在配置时,必须要写上NameServer集群地址,那么客户端到底连接的是哪个NameServer节点呢?

客户端首先会产生一个随机数,然后再与NameServer节点数量取模,此时得到的就是所要连接的节点索引,然后就会进行连接。

如果连接失败,则会采用轮询策略逐个尝试着去连接其他节点。

首先采用随机策略进行选择,失败后采用的是轮询策略

4、Broker

功能介绍

Broker相当于消息的一个中转站,负责存储消息、转发消息。

Broker在RocketMQ中负责接收并存储来自Producer发送过来的消息,同时为Consumer的Pull请求做准备。

Broker同时存储着消息相关的元数据信息,包括 Consumer Group 消费进度偏移量offset、Topic、Queue等。

Broker集群部署

为了增强Broker性能与吞吐量,Broker一般都是以集群形势存在的。各集群节点中可能存放相同的Topic的不同的Queue。

但是会出现某个节点的Broker节点宕机,那么如何保证数据不丢失呢?

解决方案是,将每个Broker集群节点进行横向扩展,即将Broker节点再建为一个HA集群,解决单点问题。

Broker节点集群是一个主从集群,即Master与Slave。Master负责处理读写操作请求,Slave负责对Master中数据备份。

当Master挂了,Slave则会自动切换成Master去工作。一个Master可以包含多个Slave,一个Slave只属于一个Master。

Master与Slave通过指定相同的BrokerName、不同的BrokerId来确定的。BrokerId为0表示Master,非0表示Slave。

每个Broker与NameServer集群中的所有节点进行长连接,定时注册Topic信息到所有NameServer。

5、工作流程

具体流程

1)启动NameServer,NameServer启动后开启监听端口,等待Broker、Producer、Consumer连接。

2)启动Broker时,Broker会与所有的NameServer建立并保持长连接,然后每30秒向NameServer定时发送心跳包。

3)发送消息前,可以先创建Topic,创建Topic时需要指定该Topic要存储到哪些Broker上,当然,在创建Topic时,也会将Topic与Broker的关系写入到NameServer中。

不过这是可选的,也可以在发送消息的时候自动创建Topic。

4)Producer发送消息,启动时先跟NameServer集群中的其中一个节点建立长连接,并从NameServer中获取路由信息,即当前发送的Topic的Queue与Broker地址的映射关系。

根据算法从中选择一个Queue,与Queue所在的Broker建立长连接,从而向Broker发消息。

当然,在获取到路由信息后,Producer会首先将路由信息缓存到本地,再每30秒从NameServer更新一次路由信息。

5)Consumer跟Producer类似,跟其中一个NameServer建立长连接,获取其订阅Topic的路由信息,然后根据算法从路由信息获取到所要消费的Queue,

然后直接根据Broker建立长连接,开始消费message。Consumer在获取到路由信息后,同样也会每30秒向NameServer更新一次路由信息。

不过不同于Producer的是,Consumer还会向Broker发送心跳,以确保Broker的存活状态

Topic创建模式

1)手动创建Topic:

  集群模式:该模式下创建的Topic在该集群中,所有的Broker中的Queue数量是相同的。

  Broker模式:该模式下创建的Topic在该集群中,每个Broker中的Queue数量可以不同。

2)自动创建Topic时,默认采取的是Broker模式,会为每个Broker默认创建4个Queue。

读写队列

从物理上来讲,读写队列是同一个队列。所以,不存在读写队列数据同步问题。读写队列从逻辑上进行分区的概念。一般情况,读写队列数量是相同的。

例如:创建Topic时,设置写队列数量为4,读队列数量为8,此时会创建8个Queue,分别是01234567。Producer会将message写入0123这4个队列,但

Consumer只会从01234567中消费,4567中是没有消息的。假设Consumer Group中包含两个Consumer,Consumer1消费0123,Consumer2消费4567。

但实际情况,Consumer2是没有消息可消费的。

 

这样设计的目的是方便Topic的Queue的缩容。

 

perm用于设置对当前创建Topic的操作权限:2表示只写,4表示只读,6表示读写

posted @   大鹏同学  阅读(302)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示