RabbitMQ快速入门以及SpringAMQP使用基础

初始MQ

同步通讯

微服务间基于Feign的调用就属于同步方式,存在一些问题

缺点:

  • 耦合度高:每次加入新的需求,都需要改原来的代码。
  • 性能下降,吞吐量下降:调用者需要等待服务提供者响应,如果调用链过长则响应时间等于每次调研时间之和。
  • 资源浪费:调用链中的每个服务在等待响应过程种,不能释放请求占用的资源,高并发场景下会极度浪费系统资源。
  • 级联失败:如果服务提供者出现问题,所有调用方都会跟着出现问题,如同多米诺骨牌效应,迅速导致整个微服务集群故障。

优点:

  • 时效性较强,可以立即得到结果。

异步通讯

异步调用常见实现就是事件驱动模式

优点:

  • 服务解耦
  • 性能提升,吞吐量提高
  • 故障隔离,服务没有强依赖,不担心级联失败问题
  • 流量削峰

缺点:

  • 依赖于Broker的可靠性、安全性、吞吐能力
  • 架构复杂了,业务没有明显的流程先,不好追踪管理

MQ常见框架

MQ(MessageQueue),中文是消息队列,字面来看就是存放消息的队列,也就是事件驱动架构种的Broker。

🚀️RabbitMQActiveMQRocketMQKafka
公司/社区RabbitApache阿里Apache
开发语言ErlangJavaJavaScala&Java
协议支持AMQP、XMPP、SMTP、STOMPOpenWire、STOMP、REST、XMPP、AMQP自定义协议自定义协议
可用性一般
单机吞吐量一般非常高
消息延迟微秒级毫秒级毫秒级毫秒级
消息可靠性一般一般

RabbitMQ快速入门(多看官方文档的案例)

RabbitMQ概述和安装

RabbitMQ是基于Erlang语言开发的开源消息通信中间件,Erlang是一个面向并发的编程语言,天生就是为了分布式系统来设计的。官网地址:https://www.rabbitmq.com

使用Docker部署RabbiteMQ

  • 在线拉取docker镜像 docker pull rabbitmq:3-management
  • 创建容器并运行docker run
    -e RABBITMQ_DEFAULT_USER=panda
    -e RABBITMQ_DEFAULT_PASS=123456
    –name mq
    –hostname mq1
    -p 15672:15672
    -p 5672:5672
    -d
    rabbitmq:3-management
  • -h --hostname:设置RabbitMQ主机名

在这里插入图片描述

总结

RabbitMQ种的几个概念:

  • channel:操作MQ的工具
  • exchange:路由消息到队列中–交换机
  • queue:缓存消息
  • cirtualHost:虚拟主机,是对queue、exchange等资源的逻辑分组

简单队列

发布者:

        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.发送消息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("发送消息成功:【" + message + "】");

        // 5.关闭通道和连接
        channel.close();
        connection.close();

消费者:


        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("guest");
        factory.setPassword("guest");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println("接收到消息:【" + message + "】");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
        System.out.println("等待接收消息。。。。");

总结

基本消息队列的消息发送流程:
1、建立connection
2、创建channel
3、利用channel声明队列
4、利用channel向队列发送消息
基本消息队列的消息接受流程:
1、建立connection
2、创建channel
3、利用channel声明队列
4、定义consumer的消费行为handleDelivery()
5、利用channel将消费者与队列绑定

SpringAMQP

AMQP(Advanced Message Queuing Protocol),是用于在应用程序或之间传递业务消息的开放标准。该协议与语言和平台无关,更符合微服务中独立性的要求。

SpringAMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接受消息。包含两部分,其中spring-amqp是基础抽象,spring-rabbit是底层的默认实现。

  • 用于异步处理入站消息的侦听器容器
  • 兔子发送和接收消息的模板
  • RabbitAdmin,用于自动声明队列,交换和绑定

简单模型

❤️ 案例-利用SpringAQMP实现Hello World中的基础消息队列功能

  1. 父工程中引入spring-amqp的依赖
  2. 在publisher服务中利用RabbitTemplate发送消息到simple.queue这个队列
  3. 在consumer服务中编写消费逻辑,绑定simple.queue这个队列
  4. 所有代码参考-mq-demo项目工程

消息一旦消费就会从队列中删除,RabbitMQ没有回溯功能

WorkQueue工作队列

在这里插入图片描述

Work Queue,工作队列,可以提高消息处理速度,避免队列消息堆积。

❤️ 案例-模拟WorkQueue,实现一个队列绑定多个消费者

  1. 在publisher服务中定义测试方法,每秒产生50条消息,发送到simple.queue
  2. 在consumer服务中定义俩个消息监听,都监听simple.queue队列
  3. 消费者1每秒处理50条消息,消费者2每秒处理10条消息
  4. 所有代码参考-mq-demo项目工程

当运行完成后发现,俩个消费者平均分配了生产的消息,这是RabbitMQ中的消费预取限制导致的

修改application.yml文件,设置preFetch的值,可以控制预取消息的上限

spring.rabbitmq.listener.simple.prepetch=1 // 每次只能获取一条消息,处理完成才能获取下一个消息

发布(Publish)、订阅(Subscribe)

发布订阅模式与之前的区别就是允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机).

在这里插入图片描述

常见的exchange(交换机)类型:

  • Fanout:广播
  • Direct:路由
  • Topic: 话题

exchange负责消息路由,而不是存储,路由失败则消息丢失.

发布订阅 - Fanout Exchange

Fanout Exchange 会将接收到的消息路由给到每一个跟其绑定的queue

在这里插入图片描述

❤️ 案例-利用SpringAMQP演示FanoutExchange的使用

  1. 在consumer服务中,利用代码声明队列、交换机,并将俩者绑定
    1. 在consumer服务声明Exchange、Queue、Binding
  2. 在consumer服务中,编写俩个消费者方法,分别监听fanout.queue1和fanout.queue2
  3. 在publisher中编写测试方法,向itcast.fanout发送消息
  4. 所有代码参考-mq-demo项目工程

在这里插入图片描述

总结:

交换机的作用是什么:

  1. 接收publisher发送的消息
  2. 将消息按照规则路由到与之绑定的队列
  3. 不能缓存消息,路由失败消息丢失
  4. FanoutExchange的会将消息路由到每个绑定的队列

声明队列、交换机、绑定关系的Bean:

  1. 队列:Queue
  2. 交换机:Exchange-FanoutExange
  3. 绑定关系:Binging

发布订阅-DirectExchange

Direct Exchange 会将接收到的消息根据规则路由到指定的Queue,因此称为路由模式(routes)

  • 每一个Queue都与Exchange设置一个BingdingKey
  • 发布者发送消息时,指定消息的RouteingKey
  • Exchange将消息路由到BingdingKey与消息RouteingKey一致的队列

在这里插入图片描述

❤️ 案例-利用SpringAMQP演示DirectExchange的使用

  1. 利用@RabbitListener声明Exchange、Queue、RoutingKey
  2. 在consumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
  3. 在publisher中编写测试方法,向itcast.direct发送消息
  4. 所有代码参考-mq-demo项目工程

在这里插入图片描述

总结:

Direct交换机与Fanout交换机的差异

  • Fanout交换机将消息路由给每一个与之绑定的队列
  • Direct交换机根据RoutingKey判断路由给哪个队列
  • 如果多个队列具有相同的RoutingKey,则与Fanout功能类似

基于@RabbitListener注解声明队列

发布订阅-TopicExchange

TopicExchange与DirectExchange类似,区别在于routingKey必须是多个单词的列表,并且以.分割。

Queue与Exchange指定BingingKey时可以使用通配符:

在这里插入图片描述

❤️ 案例-利用SpringAMQP演示TopicExchange的使用

  1. 利用@RabbitListener声明Exchange、Queue、RoutingKey
  2. 在consumer服务中,编写两个消费者方法,分别监听topic.queue1和topic.queue2
  3. 在publisher中编写测试方法,向itcast.topic发送消息
  4. 所有代码参考-mq-demo项目工程

在这里插入图片描述

总结:

Direct交换机与Topic交换机的差异

  • direct只能一一对应消费单个的routingKey,而topic可以使用通配符*和#来匹配多个routingKey

消息转换器

❤️ 案例-测试发送Object类型消息

说明:在SpringAMQP的发送方法中,接收消息的类型是Object,也就是说我们可以发送任意对象类型的消息,SpringAMQP会帮我们序列化为字节后发送。

Spring的对消息对象处理是由org.springframework.amop.support.converter.MessageConverter来处理的。而默认实现是SimpleMessageConverter,基于JDK的ObjectOutputStream完成序列化。

如果要修改 只需顶一个MessageConverter类型的Bean即可,推荐JSON方式序列化:

  • 我们在publisher服务引入依赖
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
</dependency>
  • 我们在publisher服务声明MessageConverter
@Bean
public MessageConverter messageConverter(){
   return new Jackson2JsonMessageConverter();
}

消费者接收消息的处理:

  • 我们在consumer服务引入依赖
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
</dependency>
  • 我们在consumer服务声明MessageConverter
@Bean
public MessageConverter messageConverter(){
   return new Jackson2JsonMessageConverter();
}
  • 定义监听队列,监听object.queue队列并消费信息
@RabbitListener(queues = "object.queue") // 监听队列
public void listenSimpleQueueMessage(Map<String, Object> map) { // 发送的是什么类型,这里消费就需要是什么类型
   System.out.println("消费者接收到object.queue:" + map.toString());
}

总结:

SpringAMQP中消息的序列化和反序列化是怎么实现的?

  1. 利用MessageConverter实现的,默认是JDK的序列化
  2. 注意发送方和接收方必须使用相同的MessageConverter
  3. 消费消息时发送方发送的类型与消息的类型需要一致
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值