13-RabbitMQ&SpringAMQP
初识MQ
同步通讯
同步通讯是实时的,时效性更好,可以立即得到结果。异步通讯是缓存的,时效性差一些。同步通讯无法多线程与多个客户端通讯,但是异步通讯可以。
之前使用feign调用就是同步的,调用链可能会很长或者很多,这时客户端要处在等待状态,性能会出现卡顿,并且资源没有释放。
使用feign进行调用时,功能之间的耦合度是很高的,如果调用链添加了对其他服务的调用,那就要修改调用者的代码。
甚至调用链中出现服务宕机的情况,那在进行调用的时候就会不断的卡顿从而导致整个调用链中每个服务的资源耗尽从而服务雪崩。
同步调用的问题:
耦合度高:每次加入需求都要修改原来的代码,违背开闭原则。
性能下降:服务消费者要等待提供者的响应,这将浪费时间。
资源浪费:消费者等待过程中不会释放资源,非常浪费资源。
级联失败:调用链某个提供者宕机,则导致服务雪崩。
异步通讯
异步调用采用事件驱动模式:Broker是代理服务,服务消费者将事件推送给代理,代理去通知各个提供者去完成业务。
这种方式可以解决问题:
解耦合:添加业务可以直接添加对Broker的订阅即可;取消业务也直接取消订阅即可。
性能提升,吞吐量提高:服务消费者无需等待业务结束,可以直接返回结果。
容错:服务在处理过程中如果处理失败,不会感染到消费者。
流量削峰:高并发下,可以让每个请求都排队进行调用,降低服务提供者的并发难度。
异步调用的问题:
对Broker的依赖强,要安全可靠并且能够承受高并发。
请求路径无法追踪,出现问题不好定位。
通常情况下使用的都是同步的,因为大部分情况下都要时效性,也就是服务要有返回值来组成现在的服务结果。如果不需要返回值,并且对并发,吞吐,耦合有要求,就要使用异步调用。
常见框架
MQ message queue,消息队列,也就是事件驱动架构中的Broker。消息也就是一次方法调用,一个支付事件或者下单事件等。队列是先进先出的一种数据结构。
RabbitMQ快速入门
概述与安装
使用Docker指令安装:docker pull rabbitmq:3-management
然后运行容器进行启动:docker run -e RABBITMQ_DEFAULT_USER=root -e RABBITMQ_DEFAULT_PASS=root --name mq --hostname mq1 -p 15672:15672 -p 5672:5672 -d rabbitmq:3-management
。指令中的user和pass就是用户名和密码,hostname是主机名,可选,集群中必选。15672是管理平台UI界面,5672是消息通讯端口。
访问15672就可以看到界面:
overview就是总览,nodes里面是节点列表;connections是连接列表,channels是通道列表,具体进行数据传输的通道,exchanges交换机,queues队列,admin是管理界面。
在rabbit中创建用户还要创建虚拟主机,虚拟主机用作数据隔离,类似多租户模式,不同的用户可以访问不同虚拟主机内的信息。
常见消息模型
基于队列发送的消息模式:基本消息队列(BasicQueue)和工作消息队列(WorkQueue)
基于发布订阅(Publish Subscribe)根据交换机类型不同分为三种:广播(Fanout Exchange),路由(Direct Exchange),主题(Topic Exchange)
图中紫色部分就是交换机。
快速入门
最简单的方案就是基于消息队列模型来实现,主要包括三个角色:
可以从官网获取运行Demo:https://www.rabbitmq.com/tutorials/tutorial-one-java.html
消息发送者发送后,消息会缓存到通道中,等待接受者接入同一通道之后就会接收消息。
SpringAMQP
SpringAMQP 特征:
1-监听器容器,用于异步处理接收消息;
2-用于发送和接收消息的RabbitTemplate;
3-RabbitAdmin用于自动声明队列/交换和绑定;
简单队列接收和发送
1-父项目,引入spring-amqp依赖(当然还需要引入SpringTest用作单元测试);
2-publisher项目,往队列中发送消息;
3-consumer项目,接受队列消息;
工作队列模型
工作模式就是将消息交给多个接受者,两个接受者去接收所有消息,从而节省每个接收者接收的数量。
可以提高消息处理速度,避免消息堆积。
1-publisher每秒发送50条消息;
2-consumer定义两个监听者,并定义两个监听者处理消息效率;
上文中语句进行执行后,会发现消息会平均的发送给两个消费者。
这是因为消费者有个消息预取机制,也就是在接受消息和处理消息是分离的,接收消息后会在本地缓存再去运行,这就导致两个消费者预取的能力是一样的,从而平均的分配了消息。
默认的预取是无限,也就是无限预取。
订阅发布模式
上文中简单队列模式中,消息只能被一个消费者消费,但一般情况下,一条消息还可能被多个服务接受到,这就用到了交换机。
模型中,交换机将接收消息发送出来的消息,然后通过交换机输送到多个队列中。队列也就是服务,消费者也就是一个服务的集群。
路由只是对消息进行转发,并不做消息存储,如果出现问题那传输的消息将丢失。
Fanout模型
注意bean注入的方法的参数名必须是其他bean方法的方法名,才能进行参数注入。
启动成功后,可以在控制台UI界面看到绑定结果:
接着可以在多个接收方接收不同队列的消息:
消息发送者需要把消息发送到交换机,而不是队列了:
启动发送消息服务后,多个队列的接受者都将收到同样的消息。
Direct模型
消息发送者要在每次发送消息的时候指定一个key,交换机会根据key值发送消息到指定的队列供消费者接收。
每个队列还可以指定多个key,交换机也会把消息推送给多个队列。
实验的架构如下:
采用bean声明的方式比较麻烦,可以直接通过注解的方式进行队列监听。
此时的消息消费者代码如上图。
在UI控制台中,就可以点击进入交换机查看具体队列与key值的匹配关系:
发送消息时就可以添加key值进行发送:
Topic模型
Topic可以使用.对队列进行树状分类,并且可以借助通配符批量的、模糊的对队列进行消息推送。
实验流程如下:
实际的监听者代码如下:
同样可以在UI控制台中查看路由的信息。
在消息发送方,只需要更改key值,就可以完成消息发送:
消息转换器
coverAndSend方法中,发送的消息都是Object类型的,也就是说可以发送对象类型的数据。
在UI界面对消息进行查看时可见,消息的格式如下:
消息内容可见,数据是经过序列化的对象。这内容更大,更容易被注入。
所以,推荐使用JSON序列化方式:
第二个方法是覆盖掉默认的序列化方式为Jackson序列化方式。
消息发送后,消息接收也要进行json序列化配置:
这就要保证发送的类型和接收的类型一致。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧