MQ与SpringAMQP

本文介绍了同步和异步通信的区别,重点讲解了MQ在Java微服务中的应用,包括MQ分类(如RabbitMQ、ZeroMQ等),发布/订阅和消息传递模式,SpringAMQP的基础使用及实践案例,工作队列的工作原理,以及Exchange和Message转换器的使用。
摘要由CSDN通过智能技术生成

文章目录

  • MQ知识介绍
    • 同步和异步:
    • MQ介绍
    • MQ分类
    • MQ原理
      • 发布/订阅模式
      • 消息传递模式
  • SpringAMQP
    • SpringAMQP基础使用
      • 实践案例
      • 简单代码示例
    • WorkQueue
      • 介绍
      • 消费预取机制
    • exchange交换机
      • 介绍
      • FanoutExchange
      • DirectExchange
      • TopicExchange
    • Message转换器
      • TopicExchange
    • Message转换器

MQ知识介绍

同步和异步:

同步和异步是两种不同的通信方式,它们在数据传输过程中有各自的优势和劣势。

同步通信是指发送方和接收方在固定的时间间隔内进行数据传输。在同步通信中,发送方和接收方的时钟信号需要保持一致,以确保数据的准确传输。同步通信的优点包括实时性和可靠性,因为接收方可以立即得到发送方的数据,并且由于时钟信号的一致性,数据传输的错误率和丢失率较低。然而,同步通信也有一些缺点,例如较高的耦合度和资源消耗。由于需要等待对方的回复,因此发送方和接收方的处理过程紧密耦合在一起,这可能对性能和吞吐能力产生一定的影响。此外,同步通信也需要消耗额外的资源,例如等待时间和处理时间。

image-20231030215640995

image-20231030215729908

异步通信是指发送方可以在任何时间点开始数据传输,而接收方则需要在适当的时间点接收数据。在异步通信中,发送方不需要等待接收方的回复,因此可以随时发送数据。异步通信的优点是灵活性较高,因为发送方可以随时发送数据,而不需要等待接收方的处理结果。此外,由于不需要等待对方的回复,因此异步通信也可以降低耦合度和资源消耗。然而,异步通信也有一些缺点,例如可能会造成数据的丢失或重复传输。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

综上所述,同步和异步通信都有各自的优缺点,选择哪种通信方式取决于具体的应用场景和需求。在需要实时性和可靠性的场景中,通常使用同步通信;而在需要灵活性和降低资源消耗的场景中,则通常使用异步通信。

MQ介绍

在当今的软件开发领域,微服务架构和MQ(消息队列)已成为核心组成部分。Java微服务为开发人员提供了轻量级、可扩展的解决方案,而MQ则帮助我们在分布式系统中实现异步通信和数据流动。本学习笔记将带你深入了解Java微服务和MQ的相关知识。

MQ分类

在Java微服务中,常见的MQ包括以下几种:

  1. RabbitMQ:开源消息代理软件,支持多种消息队列协议,如AMQP、STOMP和MQTT。它提供了丰富的客户端库,方便与Java微服务集成。

  2. ZeroMQ:高性能的异步消息库,适用于构建分布式和并发应用程序。它支持多种语言,包括Java。

  3. Apache Kafka:分布式流处理平台,广泛应用于实时数据流处理场景。Kafka与Java微服务结合使用可以实现高吞吐量、可扩展的分布式消息传递。

  4. ActiveMQ:开源消息代理,支持多种协议,如AMQP、STOMP和MQTT。ActiveMQ提供了灵活的配置选项和强大的API,可轻松地与Java微服务集成。

    image-20231030221245728

MQ原理

发布/订阅模式

发布/订阅模式是MQ的基本原理之一。在此模式下,生产者(发布者)将消息发布到一个或多个主题(Topic),而消费者(订阅者)则订阅感兴趣的主题并接收消息。这种模式实现了消息的解耦和灵活性,允许消费者按需接收消息。

消息传递模式

消息传递模式描述了如何在生产者和消费者之间传递消息。以下是一些常见的消息传递模式:

  1. 点对点(Point-to-Point):生产者将消息发送给一个消费者,待消费者处理完后返回确认。这种模式下,生产者等待消费者的确认,确保消息被成功处理。
  2. 发布/订阅(Pub/Sub):生产者将消息发布到一个或多个主题,多个消费者可以订阅这些主题并接收消息。这种模式下,消费者之间解耦,生产者和消费者之间也解耦。
  3. 路由(Routing):生产者将消息发送给一个中间代理(Broker),由Broker根据路由规则将消息路由给一个或多个消费者。这种模式下,生产者和消费者之间解耦,但消费者之间可能存在竞争条件。
  4. 队列(Queue):生产者将消息发送到一个队列,由一个消费者从队列中取出并处理消息。这种模式下,实现了生产者和消费者之间的解耦,但只有一个消费者可以处理该队列的消息。

SpringAMQP

在Java微服务中集成MQ需要考虑以下几个方面:

  1. 选择合适的MQ:根据项目需求选择合适的MQ,如RabbitMQ、ZeroMQ、Apache Kafka或ActiveMQ等。选择时需考虑性能、可靠性、易用性等因素。
  2. 引入依赖:在Java项目中引入所选MQ的依赖库或SDK,以便在代码中使用相关API。
  3. 定义消息格式:设计并定义消息的格式和结构,包括消息头、消息体等。同时,还需考虑如何处理异常和错误情况。
  4. 生产者与消费者的实现:在Java微服务中实现生产者和消费者逻辑。生产者负责将消息发送到MQ,而消费者则从MQ中接收并处理消息。
  5. 配置与优化:根据项目需求对MQ进行配置和优化,如设置消息确认机制、调整重试次数等。同时,还需对集成过程中可能出现的性能瓶颈进行优化。
  6. 监控与管理:对集成的MQ进行实时监控和管理,以便及时发现问题并进行调优。此外,还需制定相应的维护和管理策略,确保系统的稳定性和可靠性。

SpringAMQP基础使用

AMQP全称是Advanced Message Queuing Protocol,即高级消息队列协议

image-20231030230904443

使用Spring AMQP的流程可以概括为以下几个步骤:

  1. 引入依赖:在项目的构建文件(如Maven或Gradle)中添加Spring AMQP的依赖项,以便引入相关的库和类。

    image-20231031003228865

  2. 配置RabbitMQ连接:在Spring应用程序的配置文件中,配置RabbitMQ连接的相关信息,包括主机名、端口号、用户名、密码以及虚拟主机等。

    image-20231031003609085

  3. 创建消息生产者:使用Spring AMQP的模板类(如AmqpTemplate)来发送消息。可以通过注入AmqpTemplate实例,并调用其convertAndSend方法来发送消息。

    image-20231031003637024

  4. 创建消息消费者:使用Spring AMQP的模板类(如AmqpTemplate)来接收消息。可以通过注入AmqpTemplate实例,并调用其receive方法来接收消息。

    image-20231104144852780

  5. 定义消息队列:在RabbitMQ中定义消息队列,以便生产者和消费者可以发送和接收消息。可以使用Spring AMQP的声明方式来定义队列,也可以使用RabbitMQ的管理界面进行手动创建。

  6. 配置消息转换器:如果生产者和消费者之间的消息类型不匹配,可以使用Spring AMQP提供的消息转换器(如MessageConverter)将消息进行转换。

  7. 启动应用程序:启动Spring应用程序,并确保RabbitMQ连接已正确配置,然后生产者和消费者就可以开始发送和接收消息了。

实践案例

假设我们正在开发一个在线购物应用,用户可以浏览商品、添加到购物车、下单等。为了提高系统的可扩展性和可靠性,我们决定采用Java微服务和MQ来处理核心业务逻辑。以下是我们的实践案例:

  1. 用户浏览商品:当用户浏览商品时,前端应用程序通过API调用后端服务的“获取商品列表”接口。后端服务使用RabbitMQ将商品信息发送到“商品信息”主题,多个消费者(例如商品推荐、库存管理等服务)订阅该主题并接收消息进行处理。
  2. 添加到购物车:当用户将商品添加到购物车时,前端应用程序通过API调用后端服务的“添加商品到购物车”接口。后端服务使用RabbitMQ将购物车更新信息发送到“购物车更新”主题,购物车管理服务订阅该主题并接收消息以更新购物车数据。
  3. 生成订单:当用户完成购物并生成订单时,前端应用程序通过API调用后端服务的“生成订单”接口。后端服务使用RabbitMQ将订单信息发送到“订单信息”主题,订单处理服务订阅该主题并接收消息以处理订单。同时,支付服务会接收到支付通知,并使用RabbitMQ将支付信息发送到“支付信息”主题,财务部门服务订阅该主题并接收消息以处理支付信息。
  4. 库存管理:在生成订单时,后端服务会检查商品库存。如果库存不足,后端服务会使用RabbitMQ将库存不足信息发送到“库存通知”主题,库存管理部门服务订阅该主题并接收消息以进行库存补充。
  5. 实时推荐:推荐服务使用Apache Kafka从“商品信息”主题中获取商品信息,并使用算法进行实时推荐计算。计算结果通过Apache Kafka发送到“推荐结果”主题,前端应用程序订阅该主题并接收消息以更新推荐列表。
  6. 日志记录与分析:在整个过程中,使用日志记录工具(如ELK Stack)记录所有的操作和事件。通过分析日志,可以了解用户行为、系统性能等信息,以便进行优化和改进。

简单代码示例

这是一个简单的示例,生产者向名为hello的队列发送一个消息,消费者从该队列接收消息并打印出来。请注意,为了运行此示例,你需要在你的项目中引入RabbitMQ的Java客户端库。

生产者(Producer)

import com.rabbitmq.client.ConnectionFactory; // 导入RabbitMQ的连接工厂类  
import com.rabbitmq.client.Connection; // 导入RabbitMQ的连接类  
import com.rabbitmq.client.Channel; // 导入RabbitMQ的通道类  
import com.rabbitmq.client.DeliverCallback; // 导入RabbitMQ的交付回调接口  
  
public class Send { // 定义一个名为Send的公共类  
  private final static String QUEUE_NAME = "hello"; // 定义一个私有的静态字符串常量QUEUE_NAME,其值为"hello"  
  
  public static void main(String[] argv) throws Exception { // 定义主函数,抛出异常  
    ConnectionFactory factory = new ConnectionFactory(); // 创建一个ConnectionFactory对象,用于建立连接  
    factory.setHost("localhost"); // 设置连接的主机地址为本地主机  
    try (Connection connection = factory.newConnection(); // 创建一个新的连接,使用try-with-resources语句,自动关闭连接  
         Channel channel = connection.createChannel()) { // 创建一个新的通道,用于发送和接收消息  
        channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 声明一个名为QUEUE_NAME的队列,不持久化,不可交换,不排他,其他参数为null  
        String message = "Hello World!"; // 创建一个字符串变量message,其值为"Hello World!"  
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8")); // 将message变量以UTF-8编码的形式发送到名为QUEUE_NAME的队列中  
        System.out.println(" [x] Sent '" + message + "'"); // 打印出已发送的消息  
    }  
  }  
}

消费者(Consumer)

import com.rabbitmq.client.*; // 导入RabbitMQ的相关类库  
  
public class Recv { // 定义一个名为Recv的公共类  
  private final static String QUEUE_NAME = "hello"; // 定义一个私有的静态字符串常量QUEUE_NAME,其值为"hello"  
  
  public static void main(String[] argv) throws Exception { // 定义主函数,抛出异常  
    ConnectionFactory factory = new ConnectionFactory(); // 创建一个ConnectionFactory对象,用于建立连接  
    factory.setHost("localhost"); // 设置连接的主机地址为本地主机  
    Connection connection = factory.newConnection(); // 创建一个新的连接  
    Channel channel = connection.createChannel(); // 创建一个新的通道,用于发送和接收消息  
  
    channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 声明一个名为QUEUE_NAME的队列,不持久化,不可交换,不排他,其他参数为null  
    System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); // 打印出等待消息的提示信息  
  
    DeliverCallback deliverCallback = (consumerTag, delivery) -> { // 创建一个DeliverCallback匿名内部类,用于接收消息时调用  
        String message = new String(delivery.getBody(), "UTF-8"); // 将接收到的消息转换为UTF-8编码的字符串形式  
        System.out.println(" [x] Received '" + message + "'"); // 打印出接收到的消息  
    };  
    channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {}); // 开始从名为QUEUE_NAME的队列中消费消息,自动确认消息,调用deliverCallback回调函数处理消息,其他参数为空  
  }  
}

通过Java微服务和MQ的集成,我们的在线购物应用实现了分布式、可扩展、可靠的处理流程。同时,通过实时推荐等功能提升了用户体验,通过日志记录和分析为运营和开发团队提供了重要的数据支持。

WorkQueue

介绍

工作队列(workqueue)是一种用于在Linux系统中实现中断处理“下半部”的机制。它能够将一些不那么特别紧急且需要一定时间执行的任务延后执行,将工作项封装成函数交给工作队列执行,函数的执行环境从中断环境变成了线程环境。

工作队列内部有一个工作链表(worklist),链表上有很多工作项(work item)节点,可以将工作项简单理解为函数。工作队列内有一个线程一直在轮询工作链表,每次都从工作链表中取出一个工作项,并执行其相关联的函数。当工作队列为空时,线程会被挂起。

在RT-Thread中,有workqueue组件,通过导入头文件#include <ipc/workqueue.h>即可使用。它能够根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。

消费预取机制

image-20231104150515359

exchange交换机

介绍

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在RabbitMQ中,交换机(Exchange)是生产者发送消息不会直接将消息投递到队列中,而是先将消息投递到交换机中,再由交换机转发到具体的队列。

Exchange可以分为四种类型:直连交换机(Direct Exchange)、主题交换机(Topic Exchange)、扇形交换机(Fanout Exchange)和组交换机(Group Exchange)。

直连交换机是一种带路由功能的交换机,一个队列会和一个交换机绑定,除此之外再绑定一个routing_key,当消息被发送的时候,需要指定一个binding_key,这个消息被送达交换机的时候,就会被这个交换机送到指定的队列里面去。同样的一个binding_key也是支持应用到多个队列中的。这样当一个交换机绑定多个队列,就会被送到对应的队列去处理。

FanoutExchange

image-20231104154912078

image-20231104155128587

DirectExchange

image-20231104155603469

image-20231104160517430

image-20231104160530197

image-20231104160557840

TopicExchange

image-20231104161300193

Message转换器

image-20231104162915280

[外链图片转存中…(img-HsCzsOkg-1699087191433)]

[外链图片转存中…(img-u9DB8ySe-1699087191434)]

TopicExchange

[外链图片转存中…(img-0a59Gkou-1699087191434)]

Message转换器

[外链图片转存中…(img-LzTmeWA5-1699087191434)]

image-20231104163052583

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值