Java 八股文:MQ 篇
3 - MQ 篇
消息中间件用于分布式系统中程序之间的异步通信。它基于消息的发布/订阅或点对点机制,实现高效、可靠、可伸缩的消息传递。
3.1 RabbitMQ
3.1.1 RabbitMQ 如何保证消息不丢失?消息丢失了怎么办?
如何保证消息不丢失?
- 开启生产者 确认机制,确保生产者的消息 ack 能到达队列。
- 开启 持久化功能,确保消息未消费前在队列中不会丢失
- 开启消费者 确认机制 auto,由 spring 确认消息处理成功后完成 ack。
- 开启消费者 失败重试机制,多次失败后将消息投递到 异常交换机,交由人工处理。
消息丢失了怎么办?
生产者发送消息失败:消息未能成功发送到MQ。
消息重发:生产者应实现自动重试机制。
本地存储:在发送失败时,将消息暂存至本地(数据库或文件系统)。
日志记录:记录失败详情,便于问题追踪和分析。
消息在传输过程中丢失:消息在生产者到MQ或MQ到消费者传输过程中丢失。
- 消息重发:生产者应实现消息重发机制。
消息队列内部消息丢失:MQ内部故障,如节点崩溃或磁盘故障。
高可用配置:通过集群配置提高容错能力。
事务日志:如RabbitMQ配置消息日志,Kafka使用事务日志。
备份与恢复:定期备份消息和队列状态,以便硬件故障时恢复。
消费者处理消息时丢失:消费者在处理消息过程中发生异常。
消息重发:生产者配合实现消息重发。
未确认消息重发:MQ将未确认消息重新放回队列。
死信队列:消息处理失败或超时后转移到死信队列。
3.1.2 RabbitMQ 怎么保证消息的顺序性?怎么避免消息重复消费?
保证消息的顺序性的方法:
单一消费者:可以将消息队列的消费者数量设置为1,这样就可以保证消息的顺序性。
分区消费:将消息按照不同的分区进行发送和消费,每个分区只有一个消费者,这样可以保证每个分区的消息顺序性。
消息排序:在消息队列中添加消息排序的功能,根据消息的ID或者其他标识进行排序,保证消息的顺序性。
避免消息重复消费的方法:
消息去重:可以记录已经消费过的消息的 ID 或者其他标识,再次消费时先进行判断,如果已经消费过则跳过该消息。
消费者确认机制:消费者在消费完一条消息后,需要向消息队列发送确认消息,告诉消息队列这条消息已经被消费。
如果消息队列没有收到确认消息,则会将该消息重新发送给其他消费者进行消费。
幂等性处理:在消费消息时,可以使用幂等性处理来保证消息不被重复消费。
幂等性处理指的是对于同一个操作,多次执行所产生的结果是一致的,不会产生副作用。
3.1.3 RabbitMQ 延迟队列有了解过嘛?
- 死信队列:
- 当消息无法被正常消费时(如被拒绝或过期),会被发送到死信队列中。
- 可以通过设置消息的TTL(Time To Live)来实现延迟效果。
- 插件方式:
- 使用
rabbitmq_delayed_message_exchange
插件,可以创建延迟交换机(DelayExchange)- 在发送消息时指定
x-delay
头,该头的值即为延迟时间(毫秒)。这种方式不需要额外的死信队列配置。
3.1.4 RabbitMQ 消息堆积如何解决?
消息堆积:通常发生在生产者生产速度远大于消费者消费速度时,以下是几种解决方案:
- 增加消费者数量:在消费者机器重启后,增加更多的消费者进行处理。
- 多线程处理:在消费者处理逻辑内部开辟线程池,利用多线程的方式提高处理速度。
- 扩大队列容量:提高队列的堆积上限,但这并不是根本解决方案。
- 惰性队列:它将消息直接存储到磁盘而非内存,支持百万级消息的存储,适用于消息堆积严重的情况。
3.1.5 RabbitMQ 的高可用机制有了解过嘛?
- 集群模式:通过多节点集群部署,实现数据的冗余存储和负载均衡。
- 镜像队列:将队列的数据复制到多个节点上,即使某个节点宕机,其他节点仍然可以继续提供服务。
- Quorum 队列:类似于镜像队列,但提供了更强的一致性保证。
- 分区处理策略:在网络分区发生时,RabbitMQ 提供了自动修复、忽略和暂停少数节点等策略,以保证系统的高可用性。
3.1.6 为什么选择 RabbitMQ?有什么好处?
RabbitMQ 的功能比较丰富 , 支持各种消息收发模式(简单队列模式, 工作队列模式 , 路由模式 , 直接模式 , 主题模式等)。
支持延迟队列 , 惰性队列而且天然支持集群, 保证服务的高可用, 同时性能非常不错 , 社区也比较活跃, 文档资料非常丰富。
消息解耦:使用RabbitMQ作为中间件,可以将各个系统解耦,减少系统间的直接依赖。提升容错性和可维护性。
异步处理:将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。
使用RabbitMQ以后,可以将耗时的操作异步化,提高应用程序的响应时间,从而提高用户体验和系统吞吐量。
削峰填谷:在订单处理等场景中,可能会出现短时间内大量用户下单的情况。
通过使用RabbitMQ作为缓冲层,可以将这些订单请求分散成一段时间来处理,避免系统在峰值时过载。
消息持久化:支持消息持久化,可以保证即使在系统重启或者故障的情况下,未完成的任务也不会丢失,可以继续被处理。
多种通信协议和规则:支持多种消息通信协议和规则,例如AMQP、STOMP和MQTT等,可以满足不同应用程序的需求。
3.1.7 消息中间件的消费模式有几种?
- 单一消费者模式:一个消息队列由一个消费者进行消费,消息按照顺序逐个被处理。
- 竞争消费者模式:一个消息队列由多个消费者进行消费,消息被多个消费者竞争处理。
- 发布订阅模式:消息被发布到一个交换机,然后广播到所有队列,多个消费者从这些队列中消费消息。
- 路由模式:消息被发布到一个交换机,然后路由到特定队列,多个消费者从这些队列中消费消息。
3.2 Kafka
3.2.1 Kafka 如何保证消息不丢失?
- 消息持久化:确保所有的消息都被写入到磁盘上。
- 副本机制:每个分区的数据都保存多个副本,通常至少有三个副本。
- 同步提交:生产者在发送消息时,可以设置为同步提交,确保消息被所有副本接收后才认为是成功。
- Leader选举:当Leader副本宕机时,会从Follower副本中选举出新的Leader,保证服务的连续性。
3.2.2 Kafka 怎么保证消息的顺序性?怎么避免消息重复消费?
- 保证消息的顺序性的方法:
- 单线程消费:在同一消费者实例中,对同一个分区的消息进行顺序消费。
- 分区顺序:确保每个分区内的消息是顺序消费的,但不同分区之间的消息顺序可能不一致。
- 消费者组:在消费者组内,每个消费者负责不同的分区,可以保证分区内消息的顺序性。
- 避免消息重复消费的方法:
- 幂等生产者:确保即使消息被重复发送,处理结果也是一致的。
- 消息去重:在消费者端实现去重逻辑,比如通过业务唯一标识符来识别重复消息。
- 消费状态存储:将消费状态存储在外部存储系统中,以便在消费者重启后能够从上次消费的位置继续。
3.2.3 Kafka 的高可用机制有了解过嘛?
- 集群部署:通过多节点集群部署,实现负载均衡和故障转移。
- 数据副本:每个分区的数据都有多个副本,提高数据的可用性。
- Leader和Follower:每个分区都有一个Leader和多个Follower,Leader负责数据的读写,Follower负责数据的复制。
3.2.4 解释一下 Kafka 复制机制中的 ISR?
ISR(In-Sync Replicas)是Kafka中用于描述与Leader副本保持同步的Follower副本集合。
- 当Follower副本落后于Leader副本太多时,会被踢出ISR,此时Leader副本会等待Follower副本赶上来。
- 如果Leader副本宕机,会从ISR中选举出新的Leader。
3.2.5 为什么选择 Kafka?有什么好处?
Kafka的高性能设计包括:
- 批处理:消息以批处理的方式发送和接收,减少网络请求次数。
- 零拷贝技术:使用sendfile系统调用,减少数据拷贝的开销。
- 分区:通过分区提高并行处理能力,每个分区可以独立进行读写操作。
- 磁盘I/O优化:顺序写入磁盘,提高写入效率。
3.2.7 介绍一下 Kafka 数据存储和清理?
#java##八股文##消息队列#
- 数据存储:消息被存储在磁盘上,支持持久化。
- 日志分段:Kafka将数据存储为日志文件,每个日志文件有一个固定的大小,当达到大小时会自动创建新的日志文件。
- 日志清理:支持基于时间或日志文件大小的清理策略,如删除旧的日志文件或压缩日志文件。
- 日志压缩:对旧的日志文件进行压缩,节省存储空间。