什么是消息队列?
本质就是一个上下有通信的队列MQ(message queue),无非就是上游发送消息,消息队列存消息,下游消费消息。
为什么使用消息队列?
解耦:
例如:订单系统发放优惠券,发货,加积分,用户权益的过程。
单机环境系统和系统是耦合的,系统之间的调用可能会因为各种情况导致失败,使用MQ只需要将消息放到队列中,谁需要消费谁去取就可以了,这样系统就不需要考虑调用接口时发生的各种情况了。
异步:
例如:思考业务场景,一个商品详情页面接口,分为商品,评论,促销信息,一要从三个不同的服务获取数据,如果代码正常写,就是同步这样很慢,能不能同时开启三个线程让他们各自去执行逻辑,都成功之后收集数据统一返回。
系统直接把消息发到 MQ 中就返回,不需要等待结果,这会让用户体验比较好。
削峰:
例如:正常mysql并发量只有3, 4000这个量级,如果秒杀并发QPS到十万级别,根本顶不住,那就需要通过中间件,先把消息缓存起来,然后慢慢消费,那 为什么mysql不行的,消息队列就行?
当数据量过大时可以将数据通过消息队列进行缓存,慢慢消费。
消息队列如何保证数据不丢失?
从三方面考虑:
发送发:数据同步发送
消息队列:broker端数据持久化磁盘,主从同步
消费方:先进行消费再ack
消息重复:
出现的原因:没有ack导致发送方不断失败重试(消费方出现异常),消费方返回ack超时(弱网环境 )
解决:
因为重复消费无法避免,可以使用消息的幂等消费,可以让上游给下游传递一个唯一key比如订单就用订单号,然后下游根据这个key建立数据库唯一索引约束,每次消费的时候就可以通过这个唯一索引来判断是否已经被消费过了,已经被消费过就不用走之前的逻辑?其实很简单,为了性能还可以考虑分布式锁,比mysql快
消息积压如何解决?
1、下游增加机器
2、或者下游开启多线程消费,但是需要做好手段保证消息不丢失
3、比如说可以给线上机器磁盘扩容,阿里云各种云平台是支持这种功能的
4、其他市面上所谓的各种解决方案,把消息先放到数据库,或者先放到redis,都可以,其实这些手段最终目的都是为了缓解mq本身的磁盘压力,仅此而已
Rocketmq优点:
支持事务,支持顺序,支持死性队列,生态比较好,Java写的。
消息队列如何实现高可用?
搭建集群,主从配置,主从自动切换,数据落盘防止数据丢失(会有性能损耗)
消息队列能否保证数据顺序执行?
单条数据时可以保证的(顺序发送,同一个消息队列接受消费),多条数据无法保证数据顺序执行。
如何设计一个消息队列?
1.首先是消息队列的整体流程,制片人发送消息给经纪人,经纪人存储好,代理再发送给消费者消费,消费者回复消费确认等。
2.生产商发送消息给代理,代理发消息给消费者消费,那就需要两次RPC了,RPC如何设计呢?可以参考开源框架达博,你可以说说服务发现,序列化协议等等
3. broker考虑如何持久化呢,是放文件系统还是数据库呢,会不会消息堆积呢,消息堆积如何处理呢。
4.消费关系如何保存呢?点对点还是广播方式呢?广播关系又是如何维护呢?zk还是configserver
5.消息可靠性如何保证呢?如果消息重复了,如何幂等处理呢?
6. 消息队列的高可用如何设计呢?可以参考kafka的高可用保障机制。
7. 消息事务特性,与本地业务同个事务,本地消息落库;消息投递到服务端,本地才删除;定时任务扫描本地消息库,补偿发送。
8.MQ得伸缩性和可扩展性,如果消息积压或者资源不够时,如何支持快速扩容,提高吞吐?可以参照一下 Kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic增加 partition,然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了?
MQ常见面试题:
1.什么是消息队列?
消息队列是一种分布式系统中的通信方式,它通过异步传输消息的方式来解耦消息的生产者和消费者。在消息队列中,生产者将消息发送到一个中心化的队列中,然后消费者从队列中取出消息进行处理。
2.为什么需要使用消息队列?
使用消息队列可以解决分布式系统中的多种问题,包括异步处理、解耦、流量控制、高可用性、可伸缩性、顺序处理等问题。消息队列可以提高系统的可靠性、可扩展性、灵活性和性能。
3.什么是消息模型?
消息模型是消息队列系统中的一个概念,用于描述消息的传递方式。常见的消息模型包括点对点模型和发布/订阅模型。
点对点模型:生产者将消息发送到队列中,然后消费者从队列中取出消息进行处理。在点对点模型中,每条消息只能被一个消费者消费,即一条消息只有一个接收者。
发布/订阅模型:生产者将消息发布到主题(Topic)中,然后多个消费者订阅该主题并接收消息。在发布/订阅模型中,每条消息可以被多个消费者消费,即一条消息可以有多个接收者。
4.什么是消息堆积?
消息堆积是指消息队列中积压的消息数量超过了系统的处理能力,导致消息处理速度变慢,甚至系统崩溃的现象。消息堆积可能会导致消息的延迟和丢失,从而影响系统的可靠性和性能。
5.如何解决消息堆积的问题?
为了避免消息堆积的问题,可以采用以下几种措施:
增加消费者的数量,提高消息处理能力。
优化消息生产者的发送速率,避免发送过多的消息。
使用消息队列的自动扩缩容功能,根据系统负载自动增加或减少节点数量。
使用消息队列的延迟队列功能,将无法立即处理的消息暂时存储在延迟队列中,待系统空闲时再进行处理。
6.如何保证消息的可靠性?
为了保证消息的可靠性,可以采用以下几种措施:
使用持久化队列,将消息保存到磁盘中,避免因系统故障导致消息丢失。
使用消息确认机制,生产者在发送消息后等待消费者的确认消息,确保消息被消费。
使用消息重试机制,当消息未被确认或处理失败时,自动重发消息,确保消息被成功处理。
使用事务机制,保证消息的原子性和一致性,即要么全部消息发送成功,要么全部发送失败,避免消息发送和消费的不一致性。
使用幂等性处理,保证消息的多次处理具有相同的结果,避免消息的重复处理。
7.什么是消息延迟队列?
消息延迟队列是一种特殊的消息队列,它可以将消息延迟一定的时间后再进行处理。延迟队列通常用于处理需要在一定时间后才能处理的任务,例如订单超时未支付的处理。
8.如何保证消息顺序性?
在消息队列中,保证消息的顺序性是一个比较复杂的问题,需要考虑多个方面的因素,例如消息生产和消费的速度、消息路由的算法、消息队列的分区方式等。为了保证消息的顺序性,可以采用以下几种措施:
使用单线程消费者,保证消息的顺序性。
将消息按照顺序发送到同一个队列中,保证消息的顺序性。
使用分区的方式将消息分发到多个队列中,但保证同一个分区内的消息被处理的顺序性。
使用有序队列(如Kafka中的有序消息队列)来保证消息的顺序性。
9.什么是消息中间件的负载均衡?
消息中间件的负载均衡是指将消息队列中的消息均匀地分发到多个消费者节点上,从而实现消费者的负载均衡。常见的负载均衡算法包括轮询、随机、最小负载等算法。
10.什么是消息过滤?
消息过滤是指根据一定的规则对消息进行筛选和过滤,只将符合条件的消息发送给指定的消费者。常见的消息过滤方式包括基于主题的过滤、基于标签的过滤、基于内容的过滤等方式。通过消息过滤,可以实现更加细粒度的消息控制和处理。
11.什么是消息路由?
消息路由是指消息在消息队列中的传输路径。在消息队列中,消息可以通过不同的路由方式被分发到不同的队列或消费者节点中,例如广播、点对点等路由方式。通过灵活地设置消息路由,可以实现更加精细化的消息控制和处理。
12.什么是消息队列的持久化?
消息队列的持久化是指将消息保存在持久化存储器中,以保证即使在消息中间件重启后,消息仍然可以被恢复。消息队列的持久化通常分为两种方式:同步持久化和异步持久化。同步持久化将消息先写入到磁盘中,然后再发送到队列中,可以保证消息的可靠性和稳定性,但对性能有一定的影响;异步持久化将消息先发送到队列中,然后再异步地将消息写入到磁盘中,可以提高性能,但可能会出现消息丢失的情况。
13.如何保证消息队列的高可用性?
保证消息队列的高可用性是一个比较复杂的问题,需要从多个方面进行考虑,例如数据可靠性、故障恢复能力、性能优化等。常见的保证消息队列高可用性的措施包括:
数据备份和数据同步,保证消息队列的数据可靠性和一致性。
基于主从或集群的架构,实现故障恢复和负载均衡。
基于消息复制机制,实现消息的冗余备份,保证数据的可靠性和恢复能力。
采用高性能的存储技术,例如SSD、内存存储等,提高消息队列的性能和响应速度。
采用监控和告警机制,及时发现和处理问题,保证消息队列的稳定性和可靠性。
14.什么是消息堆积?如何解决消息堆积问题?
消息堆积是指由于消费者处理速度不足,导致消息队列中积累了大量未处理的消息,从而影响消息的传输和处理。消息堆积可能导致消息的延迟、消息的丢失、消息队列的阻塞等问题。为了解决消息堆积问题,可以采用以下几种方式:
提高消费者的处理速度,增加消费者的数量或优化消费者的代码。
调整消息队列的配置参数,例如扩大队列的容量、调整消息超时时间等。
对于无法处理的消息,可以将其丢弃或者进行重试,避免堆积占用过多的队列资源。
实现消息监控和告警机制,及时发现和处理消息堆积问题,保证消息队列的稳定性和可靠性。
15.RabbitMQ与Kafka有什么区别?
RabbitMQ和Kafka都是流行的消息中间件,但它们在设计理念、使用场景和功能特性上存在一些差异。具体来说,它们的区别包括:
设计理念:RabbitMQ采用的是AMQP(高级消息队列协议),并支持多种消息模式和路由方式,适合于较为复杂的消息场景;而Kafka采用的是发布-订阅模式,通过分区和副本机制实现消息的高可用性和可扩展性。
使用场景:RabbitMQ适合于需要实现复杂路由、事务性操作和高并发的场景,例如电商、金融等领域;而Kafka适合于需要大规模处理实时数据流的场景,例如日志、监控、推荐等领域。
功能特性:RabbitMQ提供了完整的消息确认、消息持久化、队列优先级、消息顺序等功能特性;而Kafka则提供了更加高效的消息传输和存储,支持消息的实时处理和流式计算等功能特性。
总之,RabbitMQ和Kafka都有自己独特的优势和适用场景,选择合适的消息中间件需要根据具体业务需求和技术架构进行综合评估。