Rabbit MQ 的认识和基本使用

MessageQueue

在这里插入图片描述

MQ全称是Message Queue(消息队列),是保存消息在传输过程中的一种容器,既是存储消息的一种中间件。多是应用在分布式系统中进行通信的第三方中间件,发送方称为生产者,接收方称为消费者。

在这里插入图片描述

MQ的几个主要特性
MQ的优点

解耦: 一个业务需要多个模块共同实现,或一条消息有多个系统对应处理,只需要在主业务完成以后,发送一条MQ,其余模块消费MQ消息,即可实现业务,降低模块之间的耦合。

异步: 主业务执行结束后,从属业务通过MQ异步处理,减少业务的响应时间,提高用户体验。

削峰:高并发情况下,业务异步处理,提供高峰期业务外理能力,避免系统瘫癌。

MQ的缺点
  • 系统可用性降低。依赖服务越多,服务越容易挂掉。
  • 需要考虑MQ瘫痪的情况系统的复杂性提高。
  • 需要考虑消息丢失、消息重复消费、消息传递的顺序性。
  • 业务一致性。主业务和从属业务一致性的处理
常用的MQ框架
名称特点
RabbitMQ灵活的消息路由:RabbitMQ支持多种消息路由模式。 多语言客户端支持:RabbitMQ提供了丰富的客户端库。 高可用性和可靠性:RabbitMQ支持主从复制和镜像队列,在节点故障时能够保证消息的可靠传递。 消息确认机制:RabbitMQ支持消息的确认机制,,确保消息不会丢失。
Apache Kafka高吞吐量和低延迟:Kafka被设计为高效地处理大量消息的系统,能够实现非常高的吞吐量和低延迟。 分布式架构:Kafka采用分布式架构,可以在多个节点之间进行水平扩展,实现高可用性和容错性。 消息持久化:Kafka将消息持久化到磁盘中,保证数据的可靠性和持久性。 发布-订阅模型:通过主题(topics)来组织和分类消息,消费者可以按照自己的需要订阅感兴趣的主题。 流处理能力:Kafka提供了流处理功能,在流处理应用中可以方便地处理和转换实时数据流。
RocketMQ高吞吐量和低延迟分布式架构消息持久化发布-订阅模型消息顺序性消息过滤提供轻量级的事务支持
RabbitMQ中的概念
  • channel:操作mq的工具
  • exchange:路由
  • queue:缓存消息
  • virtual host:虚拟主机,是对queue 、exchange等资源的逻辑分组
一些概念
  • P: 生产者,要发送消息的程序,不是直接发送到队列中,而是发送到交换机中。

  • C: 消费者,接收消息的程序,会一直等待消息到来。

  • Queue(红色部分): 消息队列,接收消息,缓存消息。

  • X: 交换机,即Exchange。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。具体是如何操作的,取决于Exchange的类型。Exchange有常见以下3种类型。

    常见的exchange类型:

    • Fanout:广播:将消息交给所有绑定到交换机的队列,
    • Direct:路由:把消息交给符合指定routing key的队列
    • Topic:话题:与路由模式的区别是用通配符匹配,把消息交给符合routing pattern的队列

    注意:exchange负责消息路由,而不是存储,路由失败则消息丢失。

安装MQ
  • 获取镜像

    • 查询

      • 查询docker镜像 docker search rabbitmq
    • 拉取

      • docker pull rabbitmq:3.7.7-management  
        
        #docker pull rabbitmq: 需要版本号-management  
        
  • 初始化

    • 执行命令初始化MQ容器

    • docker run \
      - e RABBITMQ_DEFAILT_USER = username \  # -e 是设置环境变量 
      - e RABBITMQ_DEFAILT_PASS = password \  #user 和 pwd
      --name mq \		#容器名
      --hostname mq1 \	#主机名,主要用于集群部署
      -p 15672:15672 \	# -p 是端口映射
      -p 5672:5672 \		#15672是管理平台的端口,5672是消息通信的端口
      -d \	# -d 是后台运行
      rabbitmq:3-management	#镜像名称
      
  • 输入上述指令,安装完成

  • 进入容器并运行

    • docker exec -it 容器id /bin/bash
      
    • rabbitmq-plugins enable rabbitmq_management
      
  • 查看管理平台界面 :15672

Spring Boot使用Rabbit MQ及API-AMQP
基本消息队列的消息发送流程
  1. 建立connection
  2. 创建channel
  3. 利用channel声明队列
  4. 利用channel向队列发送消息
基本消息队列的消息接收流程
  1. 建立connection
  2. 创建channel
  3. 利用channel声明队列
  4. 定义consumer的消费行为handleDelevery()
  5. 利用channel将消费者与队列绑定
简化消息发送与接收的API–SpringAMQP

使用:

  • 添加依赖

  •   #Gradle-kotlin
      implementation("org.springframework.boot:spring-boot-starter-amqp:3.1.0")
     
      #maven
      <dependency>
    	  <groupId>org.springframework.boot</groupId>
       	  <artifactId>spring-boot-starter-amqp</artifactId>
       	  <version>3.1.0</version>
      </dependency>
    
  • 写测试,发消息

    • 在发送服务,写配置文件

      • spring:
         rabbitmq:
          host: xxxx
          port: 5672
          username: xxx
          password: xxx
          virtual-host: xxx
        
    • 写发送测试

  • 写测试,收消息

    • 在接收服务,写配置文件,内容同上
    • 写接收测试
      • @RabbitListener 指定接收的消息队列
  • 注意:消息一旦消费就会从队列中删除,Rabbit MQ没有回溯功能

消费预取限制

修改application.yml 设施preFetch值。

spring:
 rabbitmq:
  listener:
   simple:
    prefetch: 1 #每次只能获取一条消息,处理完才能获取下一个消息;效果:效率高的服务多处理,慢的少处理
RabbitMQ的工作模式
简单模式
  1. 简单模式:一个生产者、一个消费者,不需要设置交换机(使用默认的交换机)即可。

在这里插入图片描述

Queue队列配置

 
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
 
 
@Configuration
public class QueueAndExchangeConfig {
 
    @Bean("myFirstQueue")
    public Queue getFirstQueue(){
        return new Queue("my-first-queue");
    }
}

生产者配置

 
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
 
@RestController
@RequestMapping("producer")
public class ProducerController{
 
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
    @GetMapping("/producerSendFirstQueue")
    public String sendMsg(@RequestParam(value = "msg") String msg){
        rabbitTemplate.convertAndSend("my-first-queue",msg);
        return msg;
    }
}

消费者配置

 
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
 
@Component
public class ConsumerHandler {
 
    @RabbitListener(queues = "my-first-queue")
    public void getFirstQueue(String msg){
        System.out.println("消费者1:"+msg);
    }
 
}
工作队列模式
  1. 工作队列模式 WorkQueue:一个生产者、多个消费者,对同一个消息是竞争关系,不需要设置交换机(使用默认的交换机)

在这里插入图片描述

两个消费者的配置,轮训发送消息到消费者

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
 
@Component
public class ConsumerHandler {
 
    @RabbitListener(queues = "my-first-queue")
    public void getFirstQueue(String msg){
        System.out.println("消费者1:"+msg);
    }
    
    @RabbitListener(queues = "my-first-queue")
    public void getFirstQueueTwo(String msg){
        System.out.println("消费者2:"+msg);
    }
}
发布订阅模式
  1. 发布订阅模式 Publish/subscribe:发布订阅模式允许将同一条消息发送给多个消费者。

    实现方式就是加入了exchange(交换机)。

在这里插入图片描述

将两个队列与交换器绑定

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class QueueAndExchangeConfig {
 
    //第一个队列:my-first-queue
    @Bean("myFirstQueue")
    public Queue getFirstQueue(){
        return new Queue("my-first-queue");
    }
 
    //第二个队列:my-second-queue
    @Bean("mySecondQueue")
    public Queue getSecondQueue(){
        return new Queue("my-second-queue");
    }
 
    //第一个交换机:my-first-exchange
    @Bean("myFirstExchange")
    FanoutExchange getMyFirstExchange(){
        return new FanoutExchange("my-first-exchange");
    }
 
    //将my-first-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingFirstQueueToFanoutExchange(){
        return BindingBuilder.bind(getFirstQueue()).to(getMyFirstExchange());
    }
 
    //将my-second-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingSecondQueueToFanoutExchange(){
        return BindingBuilder.bind(getSecondQueue()).to(getMyFirstExchange());
    }
 
}

两个消费者配置

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
 
@Component
public class ConsumerHandler {
 
    @RabbitListener(queues = "my-first-queue")
    public void getFirstQueue(String msg){
        System.out.println("消费者1:"+msg);
    }
 
    @RabbitListener(queues = "my-second-queue")
    public void getSecondQueue(String msg){
        System.out.println("消费者2:"+msg);
    }
 
}
路由队列(routing)
  1. 路由队列是以direct routing = key方式发送消息给消费者的

    queue 可以通过一个或多个routing key绑定到Exchange上,不同queue相同routing key绑定到Exchange也是完全可以的

queue 、 exchange 配置

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class QueueAndExchangeConfig {
 
    //省略......
 
    //将以my-first-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingFirstQueueToFanoutExchange(){
        return   BindingBuilder.bind(getFirstQueue()).to(getMyFirstExchange()).with("orange");
    }
 
    //将以my-second-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingSecondQueueToFanoutExchange(){
        return BindingBuilder.bind(getSecondQueue()).to(getMyFirstExchange()).with("green");
    }
 
}

生产者在发送消息前会绑定路由,只有路由符合规定的消费者才会接收到消息。

生产者配置

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
 
@RestController
@RequestMapping("producer")
public class ProducerController{
 
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
    @GetMapping("/producerSendFirstQueue")
    public String sendMsg(@RequestParam(value = "msg") String msg){
        rabbitTemplate.convertAndSend("my-first-exchange","green",msg);
        return msg;
    }
 
}

消费者配置

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
 
@Component
public class ConsumerHandler {
 
    @RabbitListener(queues = "my-first-queue")
    public void getFirstQueue(String msg){
        System.out.println("消费者1:"+msg);
    }
 
    @RabbitListener(queues = "my-second-queue")
    public void getSecondQueue(String msg){
        System.out.println("消费者2:"+msg);
    }
}
通配符队列 (Topics)

通配符的匹配规则:

符号作用示例
*匹配任意一个单词rabbit.* :匹配rabbit.first
#匹配任意一个或多个单词rabbit.# :匹配rabbit.first 或者 rabbit.first.two
注意如果没有匹配的路由到队列,那么该消息会丢失

简述:在上述的路由队列的路由路径的基础上进行通配。

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class QueueAndExchangeConfig {
 
    //省略.....
 
    //将以my-first-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingFirstQueueToFanoutExchange(){
        return BindingBuilder.bind(getFirstQueue()).to(getMyFirstExchange()).with("green.*");
    }
 
    //将以my-second-queue队列绑定到my-first-exchange交换机上
    @Bean
    Binding bindingSecondQueueToFanoutExchange(){
        return BindingBuilder.bind(getSecondQueue()).to(getMyFirstExchange()).with("green.#");
    }
 
}

生产者的消息路由上也有所改变,更加灵活

    @GetMapping("/producerSendFirstQueue")
    public String sendMsg(@RequestParam(value = "msg") String msg){
        rabbitTemplate.convertAndSend("my-first-exchange","green.red",msg);
        return msg;
    }
远程通讯队列

Remote Procedure Call:远程过程调用,一次远程过程调用的流程即客户端发送一个请求到服务,服务端根据请求信息进行处理后返回响应信息,客户端收到响应信息后结束

连接:RPC通信队列参考

高级应用
qos合理分发

消费预取限制

修改application.yml 设置 preFetch值。

spring:
 rabbitmq:
  listener:
   simple:
    prefetch: 1 #每次只能获取一条消息,处理完才能获取下一个消息;效果:效率高的服务多处理,慢的少处理

qos 主要应用于work queue工作队列的实现合理分发,将prefetch设置为1之后,rabbitmq会根据每个消费者的消费时间,合理分发,处理越快的消费者,处理的消息越多

ttl消息过期时间

ttl可以定义队列和消息的过期时间,如果同时设置了队列和消息的过期时间,按最小的时间删除消息,超过指定时间消息还没有被消费则会自动丢失

queue队列过期时间

@Bean("myFirstQueue")
public Queue getFirstQueue(){
    return QueueBuilder.durable("my-first-queue").ttl(30000).build();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值