为什么选择RocketMQ?
提前说明:本篇适合初学者,并没有源码解读和深入解析,文章是在自己学完之后,以更通俗易懂的话跟大家一起进入RocketMQ的世界,同时也会跟大家一起解决学习中遇到的各种各样的问题。
RocketMQ是什么:
RocketMQ 基于发布-订阅模型,生产者向主题发布消息,消费者订阅这些主题以接收消息。 它支持各种消息传递模式,例如点对点消息传递、请求-回复消息传递和流式传输。 RocketMQ提供消息排序、消息过滤、批量消息、消息追踪等功能。除了这些RocketMQ也包含了许多高级特性,详细可以看一下官方文档rocketmq.apache.org/zh/version
那为什么要选择RocketMQ呢?
我们知道目前市面上流行的消息中间件有 Kafka、RocketMQ、RabbitMQ以及来自 Yahoo 的 Pulsar。
基于为什么要选择RocketMQ我给出了以下几点自己的看法:
- 语言的优势: RocketMQ 是使用的
Java语言开发,我们公司的项目也是采用的Java语言编写,所以看官方文档有种莫名其妙的亲切感,比起RabbitMQ来说,有着更容易上手的阅读体验,也更有利于大部分同学阅读源码,分析和深入学习。 - 给足了安全感: 大家都知道
RocketMQ诞生于阿里,历年来大家熟悉的双十一等等都是用RocketMQ来承载消息,而且阿里自己也有一套比较完善的RocketMQ产品对外提供服务,由此可见RocketMQ始终保持着非常高的稳定性、可用性。 - 是否有大厂在用: 从网上多篇文章介绍中得知,
RocketMQ现在被广泛应用于各个大厂的内部业务中,其诞生之地阿里自不必多说,面对各种复杂场景,RocketMQ也交出了一份令人满意的答卷。有大厂在用,更能说明它的可靠性,同时跟随大厂的技术栈也会让自己以后有更多的机会。
除了上面三点,我自己在选择的时候,把快速入门和快速阅读理解也放到了重要的位置,并没有仔细的去对比其他中间件他们之间的差距,大致了解之后就选择了RocketMQ,也许其他的中间件也能解决我的问题,但我会把它作为后面的了解对象。
接下来就到了正题,我们都知道RocketMQ能够满足我们的需求,少不了内部的一些核心,例如Topic、Broker、Nameserver、MessageQueue等,接下来就是要了解每一个组件的用途。
Producer
生产者是 Apache RocketMQ 系统中用来构建并传输消息到服务端的运行实体。将业务消息按照要求封装成 Apache RocketMQ 的消息并发送至服务端。
Consumer
消费者是 Apache RocketMQ 中用来接收并处理消息的运行实体。 消费者通常被集成在业务系统中,从 Apache RocketMQ 服务端获取消息,并将消息转化成业务可理解的信息,供业务逻辑处理。
这里我简单了解完生产者和消费者,重点学习了以下的组件。
Broker:RocketMQ的核心
我在学习的时候看到了一个很好的例子来学习Broker,就是网购:我们平时都经常网购,快递从卖家寄出,到揽收,运输,到最后的放到货架上等待货主来取快递,这一系列流程可以类比于消息从发送到最后被消费者消费的流程,我用两张图对比一下。
Broker这个角色就是负责所有生产者发送的messgae并且将其持久化存储起来,并且同时接受消费者的请求。也就是说实际提供服务就是Broker, 也可以将它理解为消息队列的一个实例。
我们也可以暂且理解为我们发送的消息都存储在了Broker上,看到这里都会有一个问题“如果broker宕机了,那消息不就消失了吗?”
确实,如果只有一个Broker肯定不满足前面提到的高可用,所以引出了Broker集群部署,这样我们发送的消息就会分布式的存储到这几个Broker上。所以把流程图再细化一下:
大家可以简单的理解为将消息分开存储到不同的broker上,也就是如上图中画的那样,消息会被存储到3个broker上,每个Broker所存储的message不一样,但是好像并没有解决上面提到的问题,当某个Broker挂了,消息不还是丢失了么,我们需要结合学习下一个组件。
Topic:主题
主题是 Apache RocketMQ 中消息传输和存储的顶层容器,用于标识同一类业务逻辑的消息。 主题的作用主要如下:
- 定义数据的分类隔离: 在
Apache RocketMQ的方案设计中,建议将不同业务类型的数据拆分到不同的主题中管理,通过主题实现存储的隔离性和订阅隔离性。 - 定义数据的身份和权限:
Apache RocketMQ的消息本身是匿名无身份的,同一分类的消息使用相同的主题来做身份识别和权限管理。
上面是官方文档对Topic的一个详细的介绍,
大家可以理解为Topic就是一种或者一类消息的集合,比如有关订单的消息就可以创建一个Topic(order_topic),这个主题里面就是全部有关订单的消息,比如订单的创建、状态的改变...说了这么多那Topic属于队列中的那个部分呢,看一张图:
这张图向我们展示了有3个Broker 每个Boker中有不同的Topic (注意:这里的Topic是我自定义的,不用看懂,就是3个不同的Topic),这个时候流程就变成了:
之前我们只知道生产者的作用是发送消息,现在我们更清晰了一步就是,生产者发送消息的时候要指定发送到哪个Topic上,比如我这个消息是关于订单的,那我就发送到属于订单的Topic上,消费者取的时候也是如此。
到这里还没有结束,上面提到的MessageQueue好像还没出现,在了解MessageQueeu之前有几个问题。
- 某个时间段,订单疯狂增长,那么第一个
Broker要处理的消息就贼多,倒反观用户的Topic半天也没一个消息,是不是就会造成数据倾斜问题? - 还是老问题,如果第一个
Broker挂了,消息岂不是丢失了,这个Topic的出现还是没解决问题。
MessageQueue: 消息队列
队列是 Apache RocketMQ 中消息存储和传输的实际容器,也是 Apache RocketMQ 消息的最小存储单元。 Apache RocketMQ 的所有主题都是由多个队列组成,以此实现队列数量的水平拆分和队列内部的流式存储。
队列的主要作用如下:
-
存储顺序性
队列天然具备
顺序性,即消息按照进入队列的顺序写入存储,同一队列间的消息天然存在顺序关系,队列头部为最早写入的消息,队列尾部为最新写入的消息。消息在队列中的位置和消息之间的顺序通过位点(Offset)进行标记管理。 -
流式操作语义
Apache RocketMQ 基于队列的存储模型可确保消息从任意位点读取任意数量的消息,以此实现类似
聚合读取、回溯读取等特性,这些特性是RabbitMQ、ActiveMQ等非队列存储模型不具备的。
上面官方文档对MessageQueue的解释很全面,其实就是一个对于对Topic的细分,所有主题都是由多个队列组成
所以再把流程图细化一下:
可以看到每个Topic都有三个queue组成,同时分布在不同的Broker上,那也就是说,当某一时间订单这个Topic疯狂被投递消息的时候,能够均匀的分配到各个broker上去处理,这样就解决了数据倾斜问题。
已经解决了一个问题,终于到了另一个困扰大家一整节的问题,如果Broker挂了呢?之前丢失一个Topic的消息,解决了数据倾斜问题之后发现,如果Broker挂了要丢失更多的Topic的消息,问题更严重了。
根据官方文档我们可以得知RocketMQ 4.5 版本之前提供了基于主从架构的高可用机制。即将 Broker 按照角色分为 Master Broker 和 Slave Broker,主从之间会定期地进行数据同步,就像这样:
所以这个问题也得到解决了,后面再详解是怎么进行主从同步数据的。
再回顾一下整体流程,生产者生产消息并发送至 Apache RocketMQ 服务端,消息被存储在服务端的主题中,消费者通过订阅主题消费消息。
接下来,我们模拟一个场景,现在有一个有关订单的消息需要发送到order_topic上,
我们都知道生产者投递消息的时候只用指定Topic就可以了,至于这个Topic在哪个Broker上,它不用管,因为它好像也不知道这个order_topic在BrokerA上还是BrokerB上,但是在内部肯定是要指定Broker的,因为整个流程都是Broker在对外提供服务,那就代表肯定有一个组件,他既知道有多少个Broker,又知道每个Broker下有哪几个Topic,而且生产者,消费者都是通过它与Broker建立连接的。
NameServer: “上知天文,下知地理”
从标题中可以看出NameServer好像存储了很多信息,他都存储些什么呢,数据不是凭空出现的,它又是怎么知道的呢?
NameServer 都知道什么:
- 集群里都有哪些
Topic? - 这些 Topic 的
MessageQueue分别在哪些Broker上? - 集群里都有哪些活跃的
Broker? NameServer怎么知道的?
当然是 Producer、Consumer、Broker 自行将数据注册到 NameServer 的。
Broker 在启动时会将自己注册到 NameServer 上,并且通过心跳的方式持续地更新数据。此外,Producer、Consumer 都会和 NameServer 建立连接、进行交互来动态地获取集群中的数据,这样就知道自己该连接哪个 Broker 了。
我们再将流程细化一下:
这样整体的流程就通了。感觉还差点什么,就是我后来发现它有着和
Broker一样的问题。所以NameServer也是采用的集群部署。
这样下来,哪个组件是干什么的就清晰多了。
接下来为自己,也为小伙伴提出几个问题,感兴趣的可以去了解一下:
- 前面说的消息会被
Broker持久化存储起来,到底存到哪里了?如何存储的? - Broker会以
心跳的方式去注册到NameServer,心跳具体都做了哪些动作?
下一节:搭建本地环境,启动我的第一个Demo:搭建本地环境
结语
本节介绍了各种中间件的作用,如果有遇到错误的地方,或者小伙伴们有更多的理解和建议亦或者有新的问题,都可以私信或者发到评论区,大家一起学习。
紧接着在下个章节我会分享一下如何搭建本地环境,启动自己第一个demo,后续也会将如何整合Springboot发送/消费消息,再到后来的如何集群部署到线上(2主2从)等代码和流程都发出来。