3万字聊聊什么是RocketMQ

别裁伪体亲风雅,转益多师是汝师。这篇文章主要讲述3万字聊聊什么是RocketMQ相关的知识,希望能为你提供帮助。
大家好,我是Leo。
这是开端的第三次循环了。当前正在正处于RocketMQ基础原理。

??4万字聊聊阿里二面,保证你看不完??
??聊聊Redis面试题??
??3万字聊聊什么是Redis(完结篇)??
??3万字聊聊什么是MySQL(初篇)??
??2万字聊聊什么是秒杀系统(中)??
为什么需要消息队列?一个大型的系统中,随着业务量,数据体量逐渐变的复杂。越来越多的模块耦合在一起,相互调用,只要有一块出问题,几乎都是致命的。
消息队列可以解决哪些场景?
异步处理电商系统的整个流程还是非常长的,如果所有流程都同步执行的话。肯定是保证不了那么高的并发的。所以可以借助 ??RocketMQ???只要风险管控,库存锁定之后,把当前订单信息写入到 ??RocketMQ??即可返回客户端。
写到客户端之后,订单服务,用户服务,通知服务等会根据 ??Topic+Tag?? 进行消费。这步也就是 异步处理。可以提升并发量。

流量控制流量控制也就是安全问题,如何防止用户过多的请求压垮我们的秒杀系统。没加消息队列过滤的请求流程图是上述的。加了MQ过滤之后可以看如下图。

  1. 网关在收到请求后,将请求放入请求消息队列
  2. 后端服务从请求消息队列中获取 APP 请求,完成后续秒杀处理过程,然后返回结果。
如果MQ堆积了大量的秒杀请求没有处理,说明当前的后端能力小于请求压力。这个时候后端不会宕机,他会按照自己的节奏尽快的处理完MQ的所有消息。当MQ有空闲的地方空出来之后,他又会继续接收请求。
对于超时的请求可以直接丢弃,APP 将超时无响应的请求处理为秒杀失败即可。运维人员 还可以随时增加秒杀服务的实例数量进行水平扩容,而不用对系统的其他部分做任何更改
如果没有MQ作为流量控制的话,所有的请求都打到后端,后端就会宕机。
?这里MQ堆积下面会详细介绍。?
这里还可以通过令牌桶的思路来达到相同的效果。而且令牌桶的实现更简单。
?令牌桶控制流量的原理是?:单位时间内只发放固定数量的令牌到令牌桶中,规定服务在处理 请求之前必须先从令牌桶中拿出一个令牌,如果令牌桶中没有令牌,则拒绝请求。这样就保 证单位时间内,能处理的请求不超过发放令牌的数量,起到了流量控制的作用
实现的方式也很简单,不需要破坏原有的调用链,只要网关在处理 APP 请求时增加一个获 取令牌的逻辑
令牌桶可以简单地用一个有固定容量的消息队列加一个“令牌发生器”来实现:令牌发生器 按照预估的处理能力,匀速生产令牌并放入令牌队列(如果队列满了则丢弃令牌),网关在 收到请求时去令牌队列消费一个令牌,获取到令牌则继续调用后端秒杀服务,如果获取不到 令牌则直接返回秒杀失败
服务解耦先看下面两张图。一个是单体结构,一个是微服务+MQ架构。能很清晰度看出来,第二张图简单一些。就是借助的是MQ的解耦特性。为后续的维护,新增新需求,新功能。都是非常优秀的。
不管系统怎么变,任何系统都没有联系,唯一有联系的就是MQ。 系统生产系统只发给MQ,系统消费消息也是只从MQ中消费。


MQ如何选择?常用的消息队列
  • ?Kafka?:吞吐量大概在10 万级,高吞吐,支持topic。一般配合大数据类的系统来进行实时数据计算、日志采集等场景。延迟在 ms 级以内。它的可用性非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用。可以做到0丢失
  • ?RocketMQ?:10 万级,支撑高吞吐,支持topic。延迟在ms 级,可用性非常高,分布式架构。 经过参数优化配置,可以做到 0 丢失
  • ?ActiveMQ?:吞吐量大概在万级,延迟在ms级。可用性高,基于主从架构实现高可用。有较低的概率丢失数据。
  • ?RabbitMQ?:吞吐量大概在万级,延迟在微秒级,这是 RabbitMQ 的一大特点,延迟最低。可用性高,基于主从架构实现高可用。基本不丢数据
优点
上个篇幅已经介绍了。
缺点
  • ?系统可用性降低?: 俗话说,写的越多,出错的几率越大。
  • ?系统复杂度提高?:原本调用就够了,现在要接入MQ,还要做一些参数的配置,性能调优配置。加大的开发难度。
  • ?一致性问题?: 宕机后MQ未处理的消息以及已处理的消息,和数据库,和Redis的数据一致性问题
个人选型
我的技术选型是RocketMQ,主要原因如下
  1. 吞吐量在10万级,延迟低,可以做到0丢失
  2. 支持集群,确保不会因为某个节点宕机导致服务不可用,当然也不能丢消息
  3. 可用性很高,体量到了一定级别,可以采用分布式架构进行扩展
  4. 底层是用java开发的,故障排查,二次开发也是非常友好的(Java程序员)
  5. 阿里开源的,社区较为活跃,出现问题也方便解决
这里后续,经验丰富的时候会回来继续深入,技术选型。这里没那么简单!
主题和队列最初的消息队列就是我们平时简单使用的 ??Queue??,随着架构的演变,标准化跟不上演进速度,甚至到最后被废弃。
那么这个章节描述的主题和队列是什么?主题和队列又有什么关系?
队列模型
最初的队列模型就是 ?简单的先进先出(FNFO)?

业务变得越来越复杂之后,出现了多个生产者向一个消息队列里发送,然后又有多个消费者向一个消息队列里接收。这些消费者之间实际上是竞争的关系,每个消费者只能收到队列中的一部分消息,也就是说任何一条消息只能被其中的一个消费者收到。
如果需要将一份订单消息数据分发给多个消费者(用户服务,通知服务),要求每个消费者都能收到全量的消息,这个时候,单个队列就满足不了需求,一个可行的解决方式是,为每个消费者创建一个单独的队列,让生产者发送多份

显然这种方法是不可取的,违背了解耦的目的。而且每一份数据都会copy了好多份。极大的占用了内存。
为了解决这个问题,演化出了另外一种消息模型:?发布 - 订阅模型

在发布 - 订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者 (Subscriber),服务端存放消息的容器称为主题(Topic)。发布者将消息发送到主题 中,订阅者在接收消息之前需要先“订阅主题”。“订阅”在这里既是一个动作,同时还可以认为是主题在消费时的一个逻辑副本,每份订阅中,订阅者都可以接收到主题的所有消息。
在这种发布 - 订阅模型中,如果只有一个订阅者,那它和队列模型就基本是一样 的了。也就是说,发布 - 订阅模型在功能层面上是可以兼容队列模型的。
RocketMQ消息模型
RocketMQ消息模型采用的是标准的发布-订阅模型,在 RocketMQ 的术语表中,生产者、消费者和主题与我在上面 讲的发布 - 订阅模型中的概念是完全一样的。
RocketMQ也有队列的概念,在RocketMQ中是非常重要的,我们可以先看看消费机制。
?消费机制:? 几乎所有的消息队列都使用一种,简便的?(请求,确认)?机制 。确保消息不会在传递过程中由于网络或服务器故障丢失。具体的做法也非常简单。
在生产端,生产者先将消息 发送给服务端,也就是 Broker,服务端在收到消息并将消息写入主题或者队列中后,会给生产者发送确认的响应。
如果生产者没有收到服务端的确认或者收到失败的响应,则会重新发送消息;在消费端,消费者在收到消息并完成自己的消费业务逻辑(比如,将数据保存到数据库中)后,也会给服务端发送消费成功的确认,服务端只有收到消费确认后,才认为一条消息被成功消费,否则它会给消费者重新发送这条消息,直到收到对应的消费成功确认
?如下图?

这套机制很好地保证了消息传递过程中的可靠性,但是,引入这个机制在消费端带来了一个很大的问题!
为了确保消息的有序性,在某一条消息被成功消费之前,下一条消息是不能被消费的,否则就会出现消息空洞,?违背了有序性这个原则?
也就是说,每个主题在任意时刻,至多只能有一个消费者实例在进行消费,那就没法通过水平扩展消费者的数量来提升消费端总体的消费性能。为了解决这个问题,RocketMQ 在主 题下面增加了队列的概念
每个主题包含多个队列,通过多个队列来实现多实例并行生产和消费。需要注意的是, RocketMQ 只在队列上保证消息的有序性,主题层面是无法保证消息的严格顺序的。
RocketMQ 中,订阅者的概念是通过消费组(Consumer Group)来体现的。每个消费组 都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,一条消 息被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。
消费组中包含多个消费者,同一个组内的消费者是竞争消费的关系,每个消费者负责消费组 内的一部分消息。如果一条消息被消费者 Consumer1 消费了,那同组的其他消费者就不 会再收到这条消息。
在 Topic 的消费过程中,由于消息需要被不同的组进行多次消费,所以消费完的消息并不 会立即被删除,这就需要 RocketMQ 为每个消费组在每个队列上维护一个消费位置 (Consumer Offset),这个位置之前的消息都被消费过,之后的消息都没有被消费过, 每成功消费一条消息,消费位置就加一。这个消费位置是非常重要的概念,我们在使用消息 队列的时候,丢消息的原因大多是由于消费位置处理不当导致的。
【3万字聊聊什么是RocketMQ】

    推荐阅读