我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!
RocketMQ是由阿里捐赠给Apache的一款低延迟、高并发、高可用、高可靠的分布式消息中间件。
什么是消息中间件呢?
我们可以简单里"栗子",一个公司很多个部门,每个部门都有很多业务去找老板, 都要找老板,但是老板很忙啊,没办法一个一个处理啊? 那怎么办? 老板就找了个秘书, 秘书来向老板答各部门的业务,同时告诉各部门你们的事情我已经告诉老板了
这个秘书呢,就是消息中间件, 详细的专业解释,我们可以搜索了解一下;
一、为什么需要用MQ?
为什么我们需要使用MQ呢? 我们简单的微服务网上订单系统来举例!
1.1 开发中存在的痛点
1.1.1 痛点一
有些复杂的业务系统,一次用户请求可能会同步调用N个系统的接口,需要等待所有的接口都返回了,才能真正的获取执行结果。
这种同步接口调用的方式总耗时比较长,非常影响用户的体验,特别是在网络不稳定的情况下,极容易出现接口超时问题。
1.1.2 痛点二
很多复杂的业务系统,一般都会拆分成多个子系统。我们在这里以用户下单为例,请求会先通过订单系统,然后分别调用:支付系统、库存系统、积分系统 和 物流系统。
系统之间耦合性太高,如果调用的任何一个子系统出现异常,整个请求都会异常,对系统的稳定性非常不利。
1.1.3 痛点三
有时候为了吸引用户,我们会搞一些活动,比如秒杀等。
如果用户少还好,不会影响系统的稳定性。但如果用户突增,一时间所有的请求都到数据库,可能会导致数据库无法承受这么大的压力,响应变慢或者直接挂掉。
对于这种突然出现的请求峰值,无法保证系统的稳定性。
1.2 为什么要用MQ
对于上面传统模式的三类问题,我们使用mq就能轻松解决。
1.2.1 异步
对于痛点1:同步接口调用导致响应时间长的问题,使用mq之后,将同步调用改成异步,能够显著减少系统响应时间。
系统A作为消息的生产者,在完成本职工作后,就能直接返回结果了。而无需等待消息消费者的返回,它们最终会独立完成所有的业务功能。
这样能避免总耗时比较长,从而影响用户的体验的问题。
1.2.2 解耦
对于痛点2:子系统间耦合性太大的问题,使用mq之后,我们只需要依赖于mq,避免了各个子系统间的强依赖问题。
订单系统作为消息生产者,保证它自己没有异常即可,不会受到支付系统等业务子系统的异常影响,并且各个消费者业务子系统之间,也互不影响。
这样就把之前复杂的业务子系统的依赖关系,转换为只依赖于mq的简单依赖,从而显著的降低了系统间的耦合度。
1.2.3 削峰填谷
对于痛点3:由于突然出现的请求峰值,导致系统不稳定的问题。使用mq后,能够起到消峰的作用。
订单系统接收到用户请求之后,将请求直接发送到mq,然后订单消费者从mq中消费消息,做写库操作。如果出现请求峰值的情况,由于消费者的消费能力有限,会按照自己的节奏来消费消息,多的请求不处理,保留在mq的队列中,不会对系统的稳定性造成影响。
上面我们简单说明了为什么要使用MQ和MQ能帮我解决的问题
二、常见消息中间件
常见的消息中间有ActiveMQ、Kafka、RabbitMQ、RocketMQ等;大致的功能基本一致,主要是在性能上有区别,具体可以看看下图:
到此我们大概知道消息中间是什么?具体有什么作用了。
接下来我们介绍RocketMQ的概念
三、RocketMQ的核心概念及原理
3.1 RocketMQ的核心概念
首先我们需要明白RocketMQ中的几个核心概念:
-
生产者Producer
负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要。
-
消费者Consumer
负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费。
-
名字服务Name Server
名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。
-
代理服务器Broker Server
消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
-
消息主题Topic
表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。
-
消息队列MessageQueue
对于每个Topic都可以设置一定数量的消息队列用来进行数据的读取
-
消息内容Message
消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能。
-
标签Tag
为消息设置的标志,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。
3.2 RocketMQ的原理
我们举例订单服务调用库存服务的例子;
主要业务就是用户通过订单服务下单时,订单服务调用库存服务执行库存服务减去用户下单的数量;如果我想要进行解耦的话,就不能是订单服务直接调用库存服务了,中间需要加一个中间间;具体如下图:
我们来分析一下它的执行过程:
-
订单服务(消息生产者)把要传递的消息放到一个特定的对象消息内容Message中,传递大消息中间中,库存服务(消息消费者)再从消息中间件中获取到消息内容Message对象进行消费,这是一个主要流程
-
在消息中间件中有一个名字服务Name Server,它的功能类似于一个注册中心(与微服务中的Nacos类似)。同时消息中间件中可以有一个或多个代理服务器Broker Server的高可用集群的,消息中间件中存储消息,处理消息都是有它完成的;我们可以理解真正工作的是它;Broker Server和Name Server都需要要启动,
-
Broker Server会向Name Server注册服务,将自己的信息注册到Name Server中; 因为代理服务器Broker Server是可以做高可用集群的,那订单服务怎么知道找那个Broker Server?所以需要通过Name Server将Broker的地址发送给订单服务;订单服务收到后在本地就有Broket地址列表了;
注意:订单服务是不和Broker Server打交道的,也是说订单服务是不会直接去找Broker Server的,在启动的时候订单服务就会链接到Name Server了
- 当 Broker Server地址发生改变时,也会到Name Server注册服务,订单服务也会获取到最新的Broker地址列表,所以实际上调用的时候找的是本地列表进行调用可实现对Broker的负载均衡的;
注意: 因为服务于服务之间也会发送消息,所以库存服务也会和订单服务一样获取到Broker地址列表
- 在 Broker Server中会有多个消息主题Topic,Topic相当于消息发送的目的地,每个Topic中默认有4个消息队列MessageQueue,z这样有利于我降低并发度。不同的服务发送的目的地Topic是不一样,消费者会监听需要消费消息的Topic;如图:订单服务将消息发送到Broker Server中的Topic1中;库存服务中会一个监听类(开发中是我们创建的),去监听Topic中有没有消息,有就获取进行消费;
可能会有小伙伴有疑问,为什么要有对多个Topic呢?因为在实际开发中是都很多个服务的,如果每个服务都往同一个Topic中发送消息,肯定是会发现混乱的;此外就算是目前这个配置也要考虑到消息重复,顺序消费的问题,这个我们下次再详细讲;
-
消息队列MessageQueue是实际存储消息内容Message的地方,每个Topic中默认有4个消息队列MessageQueue
-
发送消息的时候可以给消息添加标签Tag,在消费者获取消息的时候可以根据Tag进行消息过滤;举个栗子:订单服务下单的时候可能下单成功也可能下单失败,那我们可以在订单消息上加上成功Tag或失败Tag,在库存服务只接受消息上打上了成功Tag的消息。
以上我简单简单的举例说明RocketMQ的核心原理和执行流程
本文主要介绍了RocketMQ的能解决的问题、核心概念和原理,本意在于分享,如果有那些漏洞和错误,万望指正;
如觉得写还可以话,感谢点赞收藏哦!!