本文主要是介绍RabbitMQ架构面试题答不出来怎么办!大佬手绘架构图带你分分钟搞懂!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
基础为什么使用 MQ?
1、削峰:在某个模块接收到超过最大承受的并发量时,可以通过 MQ 排队来使这些削减同一时刻处理的消息量。减小并发量。
2、解耦:在发送 MQ 处理业务时,可以使业务代码与当前的代码解耦,便于维护和拓展。
3、异步:异步使得在调用 MQ 后可以去处理其他操作,在 MQ 执行完后会自动反馈结果。
MQ缺点
1、复杂性提高,引入了其他问题。如消息丢失、重复消费、消息顺序执行等。这些解决方案下面会说到。
2、宕机后不可用。可以创建集群来解决。
几种 MQ 实现总结
ActiveMQ:老牌的 MQ,可靠性高,但支持的并发量低,目前维护也比较少。适用于并发量低的项目。
Kafka:支持超高并发场景,但是消息可靠性较差(消费失败后不支持重试)。适用于产生大量数据的数据收集服务。
RocketMQ:支持超高并发场景,可靠性高。但支持的客户端语言不多。适用于高并发的互联网项目。
RabbitMQ:支持一般的高并发场景(万级),可靠性高。支持客户端语言较多。但是其实现是通过 Erlang 语言,不方便学习。适用于中小型项目。
完整架构图
Java中间件面试真题 +学习笔记
Publisher:生产者,生产消息的组件。
Exchange:交换机,对生产者传来的消息进行解析并传给队列,交换机类型分为 fanout、direct、Topic、headers,其中headers交换机是根据消息对象的 headers 属性值进行匹配的,性能较差,一般不使用。
Queue:队列,因为其是 FIFO 结构,所以消息会按先进先出的顺序被发送给消费者消费。
Binding:交换机与队列的绑定关系,生产者在发送消息时会携带一个 RoutingKey ,在消息到达交换机后,交换机会根据 RoutingKey 匹配对应 BindingKey 的队列,然后把消息发送给该队列。
Virtual Host:又称为 vhost,相当于一个文件夹,包含一个或多个 Exchange 与 Queue 的组合。
Broker:表示消息队列服务器实体。
Consumer:消费者,专门消费消息的组件。
Connection:队列与消费者之间的组件,在由队列向消费者发送消息时,需要先建立连接,创建连接对象。
Channel:通道。消息由队列发送至消费者时,用于传输的通道对象。
四大核心概念指的是生产者、交换机、队列、消费者。
RabbitMQ 六种工作模式
1、Simple 简单模式
不配置交换机,生产者直接发送给队列(实际使用了默认的交换机),消费者监听队列,队列与消费者是1对1的关系。
2、work 工作模式
和简单模式差不多,同样是不配置交换机,不同的是工作模式多个消费者监听一个队列。
公平分发:在工作模式中,默认情况下多个消费者会依次接收并消费队列中的消息。
不公平分发:在工作模式中,可以在消费者端获取消息时将 channel 的参数 basicQos 设为1(默认0),那么就会在消息分发时优先选择空闲的消费者分发。如果不存在空闲队列,那么还是按公平分发。
预取值:可以看作是规定的消费者等待消费队列内部期望的队列长度。比如消费 C1 是 2,C2 是 3,那么开始的消息会先分配给 C1,直到 C1 中等待消息的消息队列长度为2时,下一个消息才会分配给 C2,然后C2也积累了3个消息后,继续C1、C2轮流分配。预期值默认为0,所以默认情况就是消费者轮流被分配消息。
配置方式也是设置消费者端的 channel 对象的 basicQos 参数。
3、publish/subscribe 订阅发布模式
交换机是 fanout 类型。交换机会将接收的消息发送给所有与其绑定的队列。
4、routing 路由模式
交换机是 direct 类型。交换机会根据接收消息的 RoutingKey 寻找匹配的 BindingKey,然后发送给对应的队列。BindingKey 是和 RoutingKey 完全匹配的,一对一关系。
5、topic 主题模式
交换机是 topic 类型。交换机会根据接收消息的 RoutingKey 寻找匹配的 BindingKey,与 routing 模式不同的是,topic 模式消息携带的 BindingKey 可以是一个通配符。交换机会匹配与通配符匹配的 BindingKey 对应的队列。* 表示任意一个单次,# 表示0个或多个单次。如果 RoutingKey 不包括通配符,那么就相当于路由模式,如果 RoutingKey 是 #,那么就相当于发布订阅模式。
6、RPC模式
RPC,也就是远程调用, RabbitMQ 的 RPC 模式可以实现 RPC 的异步调用。客户端既是发送者也是消费者,在请求发送给队列 rpc_queue 后,服务器会监听这个队列,获取后处理,处理完成将返回数据消息发给队列 reply_to,而客户端也会监听这个队列,最终实现得到结果数据。
高级死信队列
死信队列,是指消息在变成死信消息后会被发给与其绑定好的死信交换机,然后重新被死信交换机发送至新的队列,最后被消费者消费。而消息在变成死信消息的过程消耗的时间就成为了延期时间,所以常常用于实现延时队列。
死信来源
1、消息TTL过期。
2、队列内等待消费的消息达到最大长度(默认队列无长度限制)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xp6UH3kf-1626355310520)(https://upload-images.jianshu.io/upload_images/24630328-ca3461558541ed97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
3、消息在消费者被拒绝(Nack 或 reject),且不重新加入队列
延时队列实现
1、为消息设置过期时间
这种方式就是在生产者发送消息时指定消息的过期时间,等到消息在死信队列中过期后会被发送给死信交换机。
配置队列:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ztoq1zEY-1626355310525)(https://upload-images.jianshu.io/upload_images/24630328-4372cfb0bb16ccfb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
发送方:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ZkAOZom-1626355310527)(https://upload-images.jianshu.io/upload_images/24630328-b99e39ba9a33c208.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
两种方式的比较:
1、为消息设置过期时间会有一个缺陷,因为队列是先进先出结构,所以如果为消息设置过期时间,那么先进的消息一定会先被执行,后面的一定会先等到前面的消息执行完成后才被执行,如果前面的消息过期时间长于后面的,那么后面的消息即使到达过期时间后也不会被执行,必须等到前面的消息发送完才能执行。所以只适用于发送的延时消息按过期时间递增顺序的场景。
2、直接为队列设置过期时间,因为是进入队列的消息都会被分配相同的过期时间,所以不会产生上面的问题,所以也存在弊端。如果需要配置多个过期时间,那么每次都需要重新声明一个死信交换机、死信队列以及绑定关系。这样会造成配置臃肿。所以只适用于配置过期时间种类数较少的场景。
3、可以看出这两种方式都存在不足之处,有没有一种完美的方案呢?在 1 中,可以将消息按过期时间发送放在交换机里执行。因为交换机并不存在顺序执行,所以就避免了 1 的问题。
实现:
配置案例代码:
@Configurationpublic class DelayedQueueConfig {
这篇关于RabbitMQ架构面试题答不出来怎么办!大佬手绘架构图带你分分钟搞懂!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!