MQ
1. 调用的方式-掌握
1. 同步调用
- 优点:时效性较强,可以立即得到结果
- 缺点:耦合度高、性能和吞吐能力下降、有额外的资源消耗、有级联失败问题
2. 异步调用
- 优点:
-
吞吐量提升:无需等待订阅者处理完成,响应更快速
-
故障隔离:服务没有直接调用,不存在级联失败问题
-
调用间没有阻塞,不会造成无效的资源占用
-
耦合度极低,每个服务都可以灵活插拔,可替换
-
流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件
-
- 缺点
- 架构复杂了,业务没有明显的流程线,不好管理
- 需要依赖于Broker的可靠、安全、性能
2. MQ的基本介绍
1. 什么是MQ
- 掌握
- 存放消息的队列。就是事件驱动架构中的Broker
2. 常见的MQ的产品有哪些?
- 掌握
追求可用性:Kafka、RocketMQ、RabbitMQ
追求可靠性:RabbitMQ、RocketMQ
追求吞吐能力:RocketMQ、Kafka
追求消息低延迟:RabbitMQ、Kafka
3. 为什么在这个业务中需要使用MQ,为什么选择RabbitMQ或者Kafka
- 面试题
- 为什么:完成异步,解耦,削峰
- 为什么选择RabbitMQ:
- 开发语言,Erlang,为异步而生
- 消息延迟 微秒级
- 消息可靠性 高
Kafka:
- 单击吞吐量非常高
4. MQ的消息类型有哪些
-
- 不使用交换机
- 简单队列
- 工作队列:WorkQueue
-
- 使用交换机
- 广播:Fanout
- 路由:Direct
- 主题:Topic
-
MQ中的常见的消息类型有哪些?
- 面试题
- 面试题
3. MQ消息的发送和接收-重点掌握
1. 简单队列
-
- 发送消息
-
- 导入amqp的依赖
<!--AMQP依赖,包含RabbitMQ--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
- 2, 完成mq的配置
spring:
rabbitmq:
host: 192.168.150.101 # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: itcast # 用户名
password: 123321 # 密码
-
- 编写测试类
-
- 测试类上添加2个注解
-
- 通过@Autowired注入RabbitTemplate对象
-
- 发送消息
- rabbitTemplate.convertAndSend(“队列名称”, " 消息");
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSimpleQueue() {
// 队列名称
String queueName = "simple.queue";
// 消息
String message = "hello, spring amqp!";
// 发送消息
rabbitTemplate.convertAndSend(queueName, message);
}
}
-
- 消费者消费消息
-
- 导入amqp的依赖
- 2, 完成mq的配置
-
- 编写一个消费者的类
@Component
public class SpringRabbitListener {
@RabbitListener(queues = "simple.queue")
public void listenSimpleQueueMessage(String msg) throws InterruptedException {
System.out.println("spring 消费者接收到消息:【" + msg + "】");
}
}
2. 工作队列模式
让多个消费者绑定到一个队列,共同消费队列中的消息
-
- 生产者
- 本质跟简单队列一样
-
- 消费者
-
- 编写多个消费者监听同一个队列
-
- 多个消费者之间对于同一个消息是竞争关系
-
- 对于多个消费者来说消息分配的时候使用的是平均分配、
@RabbitListener(queues = "simple.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {
System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
Thread.sleep(20);
}
@RabbitListener(queues = "simple.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {
System.err.println("消费者2........接收到消息:【" + msg + "】" + LocalTime.now());
Thread.sleep(200);
}
能者多劳:
spring:
rabbitmq:
listener:
simple:
prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息
3. 广播模式
-
- 编写一个配置类完成交换机 队列 绑定关系的申明
-
声明交换机
-
public FanoutExchange fanoutExchange(){@Bean
return new FanoutExchange(“itcast.fanout”);
}
-
-
队列
-
public Queue fanoutQueue1(){@Bean
return new Queue(“fanout.queue1”);
}
-
-
绑定队列和交换机
-
public Binding binding1(Queue fanoutQueue1, FanoutExchange fanoutExchange){@Bean
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
-
-
- 编写多个消费者监听不同的队列
-
- 生产者发送消息到交换机
- rabbitTemplate.convertAndSend(“itcast.fanout”,“”, "hello fanout ");
- 易错点:routingkey只能是双引号的空不能是null
4. 路由模式
-
- 使用注解的方式申明交换机 队列 绑定关系
/**
* Direct路由
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
key = {"red","yellow"}
))
public void listenDirectQueue1(String msg){
System.out.println("消费者1接收到direct.queue1的消息:"+ msg);
}
-
推荐使用注解
-
2. 编写生产者
@Test
void testSendDirectExchange() {
//队列名称
String queue = "itcast.direct";
//消息
String msg = "hello 大角牛";
//发送消息
rabbitTemplate.convertAndSend(queue, "yellow", msg);
}
- 注意发送的routingkey
5. 主题模式
-
- 使用注解的方式申明交换机 队列 绑定关系
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue2"),
exchange =@Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC) ,
key = "#.news"
))
public void listenTopicQueue2(String msg){
System.out.println("消费者接收到topic.queue2的消息:"+msg);
}
-
- 编写生产者
rabbitTemplate.convertAndSend(queue,"plus.news",msg);
- 注意发送的routingkey
6. 发送对象消息
JDK序列化方式并不合适。我们希望消息体的体积更小、可读性更高,因此可以使用JSON方式来做序列化和反序列化。
在publisher和consumer两个服务中都引入依赖:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.10</version>
</dependency>
配置消息转换器。在启动类中添加一个Bean即可:
@Bean
public MessageConverter jsonMessageConverter(){
return new Jackson2JsonMessageConverter();
}