1. 消息队列有哪些应用场景 ?
-
应用解耦:
提升容错性和可维护性
。如下图所示:假设有系统B、C、D都需要系统A的数据,系统A调用三个方法发送数据到B、C、D。这时,系统D不需要了,那就需要在系统A把相关的代码删掉。假设这时有个新的系统E需要数据,这时系统A又要增加调用系统E的代码。为了降低这种强耦合,就可以使用MQ,系统A只需要把数据发送到MQ,其他系统如果需要数据,则从MQ中获取即可。 -
异步提速,
提升用户体验和系统吞吐量(单位时间内处理请求的数目)
。如下图所示:一个客户端请求发送进来,系统A会调用系统B、C、D三个系统,同步请求的话,响应时间就是系统A、B、C、D的总和,也就是800ms。如果使用MQ,系统A发送数据到MQ,然后就可以返回响应给客户端,不需要再等待系统B、C、D的响应,可以大大地提高性能。对于一些非必要的业务,比如发送短信,发送邮件等等,就可以采用MQ。 -
削峰填谷,
提高系统稳定性
。如下图所示:这其实是MQ一个很重要的应用。假设系统A在某一段时间请求数暴增,有5000个请求发送过来,系统A这时就会发送5000条SQL进入MySQL进行执行,MySQL对于如此庞大的请求当然处理不过来,MySQL就会崩溃,导致系统瘫痪。如果使用MQ,系统A不再是直接发送SQL到数据库,而是把数据发送到MQ,MQ短时间积压数据是可以接受的,然后由消费者每次拉取1000条进行处理,防止在请求峰值时期大量的请求直接发送到MySQL导致系统崩溃。
使用了 MQ 之后,限制消费消息的速度为1000,这样一来,高峰期产生的数据势必会被积压在 MQ 中,高峰就被“削”掉了,但是因为消息积压,在高峰期过后的一段时间内,消费消息的速度还是会维持在1000,直到消费完积压的消息,这就叫做“填谷” -
延时队列:基于RabbitMQ的死信队列或者DelayExchange插件,可以实现消息发送后,延迟接收的效果
-
保证数据一致性:解决RPC调用失败从而降级,导致的数据不一致问题。让RPC调用改为MQ异步调用,消息在下游服务故障时堆积起来,等故障恢复后再慢慢处理,减少人工接入的成本
2. 引入消息队列会带来哪些问题 ?
-
系统可用性降低
系统引入的外部依赖越多,系统稳定性越差。一旦 MQ 宕机,就会对业务造成影响。如何保证MQ的高可用? -
系统复杂度提高
MQ 的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用。如何保证消息没有被重复消费?怎么处理消息丢失情况?那么保证消息传递的顺序性? -
一致性问题
A 系统处理完业务,通过 MQ 给B、C、D三个系统发消息数据,如果 B 系统、C 系统处理成功,D 系统处理失败。如何保证消息数据处理的一致性?
3. 如何选择合适的消息队列 ?
一般而言,不同的MQ解决方案在以下方面可能存在差异:
-
性能:包括
吞吐量
、延迟
、并发处理
能力等。不同的MQ系统在处理大量消息和高并发请求时,其性能表现可能有所不同。 -
可靠性:消息队列的
可靠性
是评估其性能的重要指标之一。这包括消息的持久化
、消息传递的可靠性
、故障恢复
能力等方面。 -
功能特性:不同的MQ系统可能提供不同的功能特性,如支持的
消息类型
、消息传递模式
、消息过滤
、消息优先级
等。 -
集成与扩展性:MQ系统的
集成性
和扩展性
也是重要的考虑因素。系统是否能够轻松集成到现有的技术栈中,以及是否支持水平扩展以满足不断增长的需求,都是需要考虑的问题。
需要根据不同业务需求,与各种消息队列产品的特点,做出选择。
4. 消息队列有哪些,以及各自的特点 ?
MQ(消息队列)是分布式系统中常用的组件,用于实现 异步通信
、系统解耦
、流量削峰
等功能。市面上有多种MQ产品,他们各自有特点和适用场景。常见的消息队列中间件包括Kafka、RabbitMQ、ActiveMQ和RocketMQ等。
-
RabbitMQ
-
特性:基于Erlang语言开发,支持多种协议(比如AMQP、SMTP)。提供了
可靠性
、持久性
、分布式
和易用性
等特点(单机12000吞吐量) - 优点:功能丰富,性能稳定。社区支持活跃。适合中小型软件公司使用
- 缺点:在高并发场景下,可能会面临性能挑战
-
特性:基于Erlang语言开发,支持多种协议(比如AMQP、SMTP)。提供了
-
Kafka
-
特性:基于Scala语言开发。支持自定义协议。是一个
分布式
、高吞吐量
的流处理平台,用于构建实时数据管道和流应用程序。(单机100万吞吐量) -
优点:可以处理海量数据,具有
高吞吐量
和低延迟
特点。适用于大数据和日志收集场景 -
缺点:
数据稳定性一般
,且无法保障消息有序性
。复杂性相对较高,需要一定技术知识与配置。此外,它更偏向于数据流处理,而不是简单的消息队列
-
特性:基于Scala语言开发。支持自定义协议。是一个
-
RocketMQ
-
特性:基于Java语言开发,支持自定义协议。是一个
高性能
、高可用
的消息队列服务(单机10万吞吐量) -
优点:对于
消息可靠性有较高要求的场景下是首选
。具有强大事务支持
、消息回溯
等功能 - 缺点:某些方面可能不如RabbitMQ和Kafka功能丰富,且社区支持相对较弱。仅支持Java
-
特性:基于Java语言开发,支持自定义协议。是一个
-
ActiveMQ
- 特性:基于Java语言开发,支持多种协议(比如AMQP、SMTP)。(单机6000吞吐量)
- 优点:功能全面,稳定性较好,适用于多种场景
- 缺点:在某些方面可能不如其他MQ产品性能优越,在处理大量消息时可能面临性能挑战。缺乏大规模应用,一般不推荐
5. 如何避免消息被重复消费 ?
消费者消费消息时采用幂等性
方案。
生产者给每一条消息添加唯一ID,消费者根据此ID做幂等性保障
以下展示了采用 分布式锁+持久层数据检查
方案,解决串行、并行的重复请求带来的幂等性问题
6. 如何保证消息消费的有序性?
其实队列天然具备先进先出的特点,只要消息的发送是有序的,那么理论上接收也是有序的。
不过当一个队列绑定了多个消费者时,可能出现消息轮询投递给消费者的情况,而消费者的处理顺序就无法保证了。
因此,要保证消息的有序性,需要做到以下几点:
- 保证消息发送的有序性
- 保证一组有序的消息都发送到同一个队列
- 保证一个队列只包含一个消费者
7. 如何避免消息堆积 ?
消息堆积问题的产生原因:消息生产速度 > 消息消费速度。
解决方案:
-
提高消费者处理速度。优化消费者业务代码,提高性能
-
增加更多消费者。一个队列绑定多个消费者,共同争抢消息
-
增加消息队列存储上限。RabbitMQ的1.8版本后,引入了新的队列模式:
Lazy Queue
该队列模式不会将消息保存在内存,而是在收到消息后直接写入磁盘,理论上无存储上限