常用消息中间件八股笔记

1.消息队列

0.什么是消息队列?

我们可以把消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。

队列Queue是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。

1.为什么要使用消息队列/消息队列有什么用?

总结一下,主要三点原因:解耦、异步、削峰

1、解耦。使用消息队列,可以避免模块之间直接调用,将所需共享的数据放在消息队列中,对于新增业务模块,只要对该类消息感兴趣,即可订阅该类消息,对原有系统和业务没有任何影响,降低了系统各个模块的耦合度,提高了系统的可扩展性。

2、异步。消息队列允许生产者将消息发送到队列中,而不需要等待消费者立即处理。这样可以实现异步通信,提高系统的响应速度和吞吐量。

3、削峰。消息队列可以将消息存储起来,供消费者在适当的时间进行处理,从而实现延迟处理。高峰期的消息可以被积压起来,在随后的时间内进行平滑的处理完成,而不至于让系统短时间内无法承载而导致崩溃。在电商网站的秒杀抢购这种突发性流量很强的业务场景中,消息队列的强大缓冲能力可以很好的起到削峰作用。

2. 使用了消息队列会有什么缺点

  • 系统可用性降低。引入消息队列之后,如果消息队列挂了,可能会影响到业务系统的可用性。
  • 系统复杂性增加。加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。

3.RabbitMQ和Kafka的对比

  • 应用场景方面 **RabbitMQ:用于实时的,对可靠性要求较高的消息传递上。**性能极其好,延时很低,达到微秒级。社区成熟且活跃,提供完善的文档和插件支持 Kafka:用于处于活跃的流式数据,大数据量的数据处理上。提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集
  • 架构模型方面

​ RabbitMQ:以broker为中心,有消息的确认机制。​ Kafka:以consumer为中心,没有消息的确认机制。

  • 吞吐量方面 RabbitMQ:支持消息的可靠的传递,支持事务,不支持批量操作,基于存储的可靠性的要求存储 可以采用内存或硬盘,吞吐量小。 Kafka:内部采用消息的批量处理,数据的存储和获取是本地磁盘顺序批量操作,消息处理的效率 高,吞吐量高。
  • 集群负载均衡方面 RabbitMQ:本身不支持负载均衡,需要loadbalancer的支持。 Kafka:采用zookeeper对集群中的broker,consumer进行管理,可以注册topic到zookeeper 上,通过zookeeper的协调机制,producer保存对应的topic的broker信息,可以随机或者轮询发 送到broker上,producer可以基于语义指定分片,消息发送到broker的某个分片上。

3.MQ常用协议

  • AMQP协议 AMQP即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。优点:可靠、通用
  • MQTT协议 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统
  • STOMP协议 STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。优点:命令模式(非topic/queue模式)
  • XMPP协议 XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大
  • 其他基于TCP/IP自定义的协议:有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接口进行传输,实现了MQ的功能。

4.MQ的通讯模式

  1. 点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一、一对多、多对多、多对一等多种配置方式,支持树状、网状等多种拓扑结构。
  2. 多点广播:MQ适用于不同类型的应用。其中重要的,也是正在发展中的是"多点广播"应用,即能够将消息发送到多个目标站点(Destination List)。可以使用一条MQ指令将单一消息发送到多个目标站点,并确保为每一站点可靠地提供信息。MQ不仅提供了多点广播的功能,而且还拥有智能消息分发功能,在将一条消息发送到同一系统上的多个用户时,MQ将消息的一个复制版本和该系统上接收者的名单发送到目标MQ系统。目标MQ系统在本地复制这些消息,并将它们发送到名单上的队列,从而尽可能减少网络的传输量。
  3. 发布/订阅(Publish/Subscribe)模式:发布/订阅功能使消息的分发可以突破目的队列地理指向的限制,使消息按照特定的主题甚至内容进行分发,用户或应用程序可以根据主题或内容接收到所需要的消息。发布/订阅功能使得发送者和接收者之间的耦合关系变得更为松散,发送者不必关心接收者的目的地址,而接收者也不必关心消息的发送地址,而只是根据消息的主题进行消息的收发。在MQ家族产品中,MQ Event Broker是专门用于使用发布/订阅技术进行数据通讯的产品,它支持基于队列和直接基于TCP/IP两种方式的发布和订阅。
  4. 集群(Cluster):为了简化点对点通讯模式中的系统配置,MQ提供 Cluster 的解决方案。集群类似于一个 域(Domain) ,集群内部的队列管理器之间通讯时,不需要两两之间建立消息通道,而是采用 Cluster 通道与其它成员通讯,从而大大简化了系统配置。此外,集群中的队列管理器之间能够自动进行负载均衡,当某一队列管理器出现故障时,其它队列管理器可以接管它的工作,从而大大提高系统的高可靠性

5.多线程异步和MQ的区别

  • CPU消耗。多线程异步可能存在CPU竞争,而MQ不会消耗本机的CPU。
  • MQ 方式实现异步是完全解耦的,适合于大型互联网项目。
  • 削峰或者消息堆积能力。当业务系统处于高并发,MQ可以将消息堆积在Broker实例中,而多线程会创建大量线程,甚至触发拒绝策略。
  • 使用MQ引入了中间件,增加了项目复杂度和运维难度。

总的来说,规模比较小的项目可以使用多线程实现异步,大项目建议使用MQ实现异步。

6.MQ幂等性怎么保证/怎么解决消息重复消费问题?

MQ(消息队列)的幂等性可以通过多种措施来保证,确保系统即使在出现重复消息的情况下也能保持数据的一致性和正确性。具体如下:

  1. 生成全局唯一的inner-msg-id:在消息发送端(上半场),MQ客户端应为每条消息生成一个全局唯一且业务无关的inner-msg-id。这个ID由MQ保证其唯一性,并且对业务透明。这样,即使在网络波动或超时导致的重发情况下,MQ服务器可以利用这个ID进行去重,确保相同的消息不会被处理多次。
  2. 业务层的去重处理:在消息的消费端(下半场),业务系统需要根据业务特点带入业务相关的biz-id。消费端通过这个biz-id来进行去重,以保证对于同一业务操作,即使收到了多次相同消息,也只会被处理一次。这要求业务系统具备去重逻辑,通常涉及到数据库的唯一约束或者分布式锁等机制来保证操作的幂等性。
  3. 利用乐观锁机制:借鉴数据库中乐观锁的思想,可以为涉及状态变更的业务数据添加版本号。每次更新前先检查版本号,只有在版本号匹配的情况下才执行更新操作,并更新版本号。这种方式可以防止并发下的重复操作影响数据一致性。
  4. 消息确认机制:MQ客户端在发送消息给MQ服务器后,等待服务器的确认(ACK)。如果确认丢失或超时,客户端会重发消息。为了避免因此导致的重复消息处理,MQ服务器内部需要有机制识别并丢弃重复的消息,例如利用上述提到的inner-msg-id进行去重。
  5. 消费端幂等设计:在消费端实现业务逻辑时,需要考虑到消息可能会被重复投递的情况。因此,消费端的业务处理逻辑应当设计成幂等的,即多次执行相同的操作不会对最终结果产生影响。
  6. 事务性消息:对于需要保证精确一次消费的场景,可以使用事务性消息。这意味着消息的发送和消费是原子性的,要么都成功,要么都失败。这种方式下,系统能更好地控制幂等性,但可能会牺牲一些性能。
  7. 限流和补偿机制:在高并发场景下,适当的限流策略可以避免系统因过载而产生错误的重复操作。同时,建立补偿机制可以在检测到异常操作时进行修正。

综上所述,保证MQ幂等性是一个系统性工程,既涉及到技术层面的改进,如ID生成、去重、乐观锁等,也需要业务逻辑层面的支持,如业务去重、幂等设计等。

7.MQ 中的消息过期失效了怎么办?

如果使用的是RabbitMQ的话,RabbtiMQ 是可以设置过期时间的(TTL)。如果消息在 Queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。这时的问题就不是数据会大量积压在 MQ 里,而是大量的数据会直接搞丢。这个情况下,就不是说要增加 Consumer 消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。

我们可以采取一个方案,就是批量重导。就是大量积压的时候,直接将数据写到数据库,然后等过了高峰期以后将这批数据一点一点的查出来,然后重新灌入 MQ 里面去,把丢的数据给补回来。

8.消息队列里面拉取模式和推送模式的比较

在消息队列系统中,推送模式(Push)和拉取模式(Pull)是两种基本的消息传输机制。它们之间存在一定的区别。具体分析如下:

  • 推送模式:**在MQ中也就是Broker收到消息后主动推送给Consumer的操作,叫做推模式。**推模式的实现是客户端会与服务端(Broker)建立长连接,当有消息时服务端会通过长连接通道将消息主动推送给客户端,这样客户端就能实时消费到最新的消息。优点: 实时性强,有消息立马推送给客户端,吞吐量大。客户端实现简单,只需要监听服务端的推送即可。缺点: 容易导致客户端发生消息堆积的情况,因为每个客户端的消费能力是不同的,如果简单粗暴的有消息就推送,就会会出现堆积情况。
  • 拉取模式:在MQ中也就是客户端主动从服务器Broker端获取信息。很多拉模式都是基于长轮询来实现。长轮询就是客户端向服务端发起请求,如果此时有数据就直接返回,如果没有数据就保持连接,等到有数据时就直接返回。如果一直没有数据,超时后客户端再次发起请求,保持连接,这就是长轮询的实现原理。很多的开源框架都是用的这种方式,比如配置中心Apollo的推送优点: 不会造成客户端消息积压,消费完了再去拉取,主动权在自己手中。长轮询实现的拉模式实时性也能够保证。缺点: 实时性较差,针对于服务器端实时更新的信息,客户端难以获取实时信息;

推和拉都有各自的优势和劣势,不过目前主流的消息队列大部分都用的拉模式,比如RocketMQ,Kafka。

9.如果有100万消息堆积在MQ , 如何解决 ?

我在实际的开发中,没遇到过这种情况,不过,如果发生了堆积的问题,解决方案也所有很多的

第一:提高消费者的消费能力 ,可以使用多线程消费任务

第二:增加更多消费者,提高消费速度

​ 使用工作队列模式, 设置多个消费者消费消费同一个队列中的消息

第三:扩大队列容积,提高堆积上限

可以使用RabbitMQ惰性队列,惰性队列的好处主要是

①接收到消息后直接存入磁盘而非内存

②消费者要消费消息时才会从磁盘中读取并加载到内存

③支持数百万条的消息存储

10.说一说生产者与消费者模式

所谓生产者-消费者问题,实际上主要是包含了两类线程。一种是生产者线程用于生产数据,另一种是消费者线程用于消费数据,为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库。生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为。而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。但是,这个共享数据区域中应该具备这样的线程间并发协作的功能:

\1. 如果共享数据区已满的话,阻塞生产者继续生产数据放置入内;\2. 如果共享数据区为空的话,阻塞消费者继续消费数据。在Java语言中,实现生产者消费者问题时,可以采用三种方式:\1. 使用 Object 的 wait/notify 的消息通知机制;\2. 使用 Lock 的 Condition 的 await/signal 的消息通知机制;\3. 使用 BlockingQueue 实现。

2.RabbitMQ

1.什么是RabbitMQ

RabbitMQ 是一个在 AMQP(Advanced Message Queuing Protocol )基础上实现的整,体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。

什么是AMQP

RabbitMQ 就是 AMQP 协议的 Erlang 的实现(当然 RabbitMQ 还支持 STOMP2MQTT3 等协议 ) AMQP 的模型架构 和 RabbitMQ 的模型架构是一样的,生产者将消息发送给交换器,交换器和队列绑定 。

RabbitMQ 中的交换器、交换器类型、队列、绑定、路由键等都是遵循的 AMQP 协议中相 应的概念。目前 RabbitMQ 最新版本默认支持的是 AMQP 0-9-1。

AMQP 协议的三层

  • Module Layer:协议最高层,主要定义了一些客户端调用的命令,客户端可以用这些命令实现自己的业务逻辑。
  • Session Layer:中间层,主要负责客户端命令发送给服务器,再将服务端应答返回客户端,提供可靠性同步机制和错误处理。
  • TransportLayer:最底层,主要传输二进制数据流,提供帧的处理、信道服用、错误检测和数据表示等。

AMQP 模型的三大组件

  • 交换器 (Exchange):消息代理服务器中用于把消息路由到队列的组件。
  • 队列 (Queue):用来存储消息的数据结构,位于硬盘或内存中。
  • 绑定 (Binding):一套规则,告知交换器消息应该将消息投递给哪个队列。

2.RabbitMQ 核心概念?

0.Message消息体

Message:由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key、priority、delivery-mode(是否持久性存储)等。

1.Producer(生产者) 和 Consumer(消费者)

  • Producer(生产者) :生产消息的一方
  • Consumer(消费者) :消费消息的一方

消息一般由 2 部分组成:消息头(或者说是标签 Label)和 消息体。消息体也可以称为 payLoad ,消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括 routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。生产者把消息交由 RabbitMQ 后,RabbitMQ 会根据消息头把消息发送给感兴趣的 Consumer(消费者)。

2.Exchange(交换器)

消息并不是直接被投递到 Queue(消息队列) 中的,中间还必须经过 Exchange(交换器) 这一层,Exchange(交换器) 会把我们的消息分配到对应的 Queue(消息队列) 中。

Exchange(交换器) 用来接收生产者发送的消息并将这些消息路由给服务器中的队列中,如果路由不到,或许会返回给 Producer(生产者) ,或许会被直接丢弃掉 。

RabbitMQ 的 Exchange(交换器) 有 4 种类型,不同的类型对应着不同的路由策略direct(默认)fanout, topic, 和 headers,不同类型的 Exchange 转发消息的策略有所区别。

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java抽象带蓝子的笔记专栏 文章被收录于专栏

我的笔记专栏,内有自己整理的八股知识笔记和算法刷题笔记,我会不断通过他人和自己的面经来更新和完善自己的八股笔记。专栏每增加一篇文章费用就会上涨一点,如果你喜欢的话建议你尽早订阅。内有超详细苍穹外卖话术!后续还会更新其他项目和我的实习经历的话术!敬请期待!

全部评论
11.12日已更新,订阅我专栏后可进入我的专栏里用md格式侧边栏看该笔记体验感更好!
点赞 回复 分享
发布于 11-12 21:40 湖南

相关推荐

13 79 评论
分享
牛客网
牛客企业服务