文章目录
RabbitMQ 的作用
- 提供了系统之间的异步调用,比如一个支付功能,用户在支付完成之后,会去数据库中执行后续操作,然后更新支付状态,会生成订单信息,如果后续还需要添加功能,就需要去业务逻辑中修改代码,这样就会出现业务耦合。同时想要执行后续操作,需要等待支付功能完成,在此等待过程中会耗费时间,CPU空转,性能比较差。当业务中有操作失败,就会将全部操作回滚。如果下一个操作依赖上一个操作时就需要用到同步操作。但是后续的很多业务操作只需要知道支付成功之后就去执行,不需要等待其他业务执行完成之后再去执行。同步操作的时效性强,但是拓展性差,并且性能下降还会出现级联失败等问题。
- 异步调用的方式就是基于消息通知的方式,其中有三个角色:消息发送者、消费代理、消息接收者。微信消息发送、送外卖。支付服务就不在同步调用业务关联度低的服务,而是发送消息通知Broker,这样做具有以下优势
- 解除耦合,拓展性强。
- 无需等待,性能好。
- 故障隔离:当某一个业务接收服务宕机,其他的服务可以正常执行,这个服务重连之后只需要去MQ中去获取数据就行。
- 缓存消息,削峰填谷作用:当突然有大量的支付请求过来后,不会第一时间去冲击数据库,而是存放在MQ中,根据业务处理的速度自己去取,业务服务压力就很小。
- 异步调用的问题:
- 不能立刻得到调用结果,时效性差。
- 不确定下游业务是否执行成功。
- 业务安全依赖于Broker的可靠性。
为什么使用RabbitMQ
MQ就是MessageQueue,存放消息的队列,也就是异步调用中的Broker。
在日常开发过程中,常见的消息队列有四种,RabbitMQ、ActiveMQ、RocketMQ、Kafka。 这四中的对比性下图可以看到,其中RabbitMQ是Rabbit公司专门研究的,相较于其他消息中间件它支持SMTP协议,并且它的消息延迟更是达到了恐怖的微秒级。当然它的消息可靠性以及可用性也是非常高的,所以一般项目开发没有特殊要求都是使用的是RabbitMQ。
数据隔离
交换机和队列都有自己的VirtualHost,不同的VirtualHost都有自己不同的交换机和队列。一个MQ中可以有多个VirtualHost,在发消息的时候去连接对应的VirtualHost就行。每个user可以去操作自己创建的的VirtualHost,查看的话时根据管理员创建user时分配的权限决定。
SpringAMQP
<!--RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
rabbitmq:
host: # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: # 用户名
password: # 密码
加入RabbitMQ依赖,在yml文件中配置,然后通过RabbitTemple向队列中发送消息。
work模式
默认情况下,RabbitMQ会将消息依次轮询投递给绑定在队列上的每一个消费者。并没有考虑到消费者是否已经处理完消息,这种情况可能出现的问题就是当我们不知道消费者消费能力的时候容易出现消息堆积。比如此时有两个消费者,消费者a一秒钟可以处理50条数据,消费者b一秒钟只能处理5条数据,此时有1000条消息发送到队列中,一次轮询绑定消费者,每一个消费者绑定了500个数据,但是消费者a10秒钟就处理完成,此时消费者b还在处理消息,a此时就空闲着,可用性比较低。
因此我们需要在yml中设置prefetch值为1,确保同一时刻最多投递给消费者1条消息,处理完之后才能获取下一条消息。
Rabbitmq:
listener:
simple:
prefetch: 1
交换机
交换机主要分为三种类型:Fanout(广播)、Direct(定向)、Topic(话题)。
- Fanout:Fanout Exchange会将接收到的消息广播到每一个跟其绑定的queue中,所以也叫广播模式。
- Direct:Direct Exchange会将接收到的消息根据规则路由到指定的Queue,因此称为定向路由。
- 每一个Queue都与Exchange设置一个BindingKey。
- 发布者发布消息时,指定消息的RoutingKey。
- Exchange将消息路由到BindingKey与消息BindingKey一致的队列。
- Topic:TopicExchange与DirectExchange类似,特殊之处在于
- routingKey可以是多个单词的列表,并且以 . 分割。
- Queue与Exchange指定BinddingKey时可以使用通配符:
- #:代指0个或多个单词。
- *:代指一个单词。
如何声明队列和交换机
1. Spring AMQP提供了几个类,用来声明队列、交换机以及其绑定关系。
- Queue:用于声明队列,可以用工厂类QueueBuilder构建。
- Exchange:用于声明交换机,可以用工厂类ExchangeBuilder构建。
- Binding:用于声明队列和交换机的绑定关系,可以用工厂类BindingBuilder构建。
@Bean
public FanoutExchange fanoutExchange(){
// ExchangeBuilder.fanoutExchange("").build();
return