03:入门案例(狂神说RabbitMQ)

RabbitMQ入门案例 - Simple 简单模式

https://www.bilibili.com/video/BV1dX4y1V73G?p=44

实现步骤

  1. jdk1.8
  2. 构建一个 maven工程
  3. 导入 rabbitmq的 maven依赖
  4. 启动 rabbitmq-server服务
  5. 定义生产者
  6. 定义消费者
  7. 观察消息的在 rabbitmq-server服务中的进程

构建一个maven工程

03:入门案例(狂神说RabbitMQ)_第1张图片

导入依赖

java原生依赖

<dependency>
    <groupId>com.rabbitmqgroupId>
    <artifactId>amqp-clientartifactId>
    <version>5.10.0version>
dependency>

第一种模型

03:入门案例(狂神说RabbitMQ)_第2张图片

在上图的模型中,有以下概念:

  1. 生产者,也就是要发送消息的程序
  2. 消费者:消息的接受者,会一直等待消息到来。
  3. 消息队列:图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。

生产者

//简单模式
public class Producer{
     
    //1.创建连接工厂
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("10.15.0.9");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("admin");
    connectionFactory.setPassword("admin");
    connectionFactory.setVirtualHost("/");
    Connection connection = connectionFactory.newConnection("生产者");
    //2.创建通道
    Channel channel = connection.createChannel();
    //3.通过创建交换机,声明队列,绑定关系,路由key,发送消息和接受消息
    /*参数1: 是否持久化,非持久化消息会存盘吗?会存盘,但是会随着重启服务器而丢失
      参数2:是否独占队列 
      参数3:是否自动删除,随着最后一个消费者消息完毕消息以后是否把队列自动删除
  	  参数4:携带附属属性
    */
    String queueName = "queue1";
    channel.queueDeclare(queueName,false,false,false,null);
    //4.发送消息给队列queue
    /*参数1: 交换机
      参数2:队列、路由key
      参数3:消息的状态控制
  	  参数4:消息主题
    */
    //面试题:可以存在没有交换机的队列吗?不可能,虽然没有指定交换机但是一定会存在一个默认的交换机
    String message = "Hello";
    channel.basicPublish("",message, null,message.getBytes());
    //5.关闭
    channel.close();
    connection.close();
}

消费者

//简单模式
public class Consumer{
     
    //1.创建连接工厂
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("10.15.0.9");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("admin");
    connectionFactory.setPassword("admin");
    connectionFactory.setVirtualHost("/");
    Connection connection = connectionFactory.newConnection("生产者");
    //2.创建通道
    Channel channel = connection.createChannel();
	//3.接受内容
    channel.basicConsume("queue1",true,new DefaultConsumer(){
     
        public void handle(String consumerTag, Delivery message) throws IOException {
     
          System.out.println(new String("收到消息是" + new String(meassage.getBody()),"UTF-8"));
        },new CancelCallback(){
     
            public void handle(String consumerTag) throws IOException {
     
                System.out.println("接受失败了");
        }
      });
    //4.关闭
    channel.close();
    connection.close();
}

什么是AMQP

什么是AMQP

AMQP全称:Advanced Message Queuing Protocol(高级消息队列协议)。是应用层协议的一个开发标准,为面向消息的中间件设计

AMQP生产者流转过程

03:入门案例(狂神说RabbitMQ)_第3张图片

AMQP消费者流转过程

03:入门案例(狂神说RabbitMQ)_第4张图片

RabbitMQ的核心组成部分

RabbitMQ的核心组成部分

03:入门案例(狂神说RabbitMQ)_第5张图片

03:入门案例(狂神说RabbitMQ)_第6张图片

RabbitMQ整体架构是什么样子的?

03:入门案例(狂神说RabbitMQ)_第7张图片

RabbitMQ的运行流程

03:入门案例(狂神说RabbitMQ)_第8张图片

RabbitMQ支持的消息模型

在这里插入图片描述

在这里插入图片描述

  1. 简单模式 Simple
  2. 工作模式 Work
  3. 发布订阅模式
  4. 路由模式
  5. 主题 Topic模式
  6. 参数模式

RabbitMQ入门案例 - fanout 模式

RabbitMQ的模式之发布订阅模式

图解

03:入门案例(狂神说RabbitMQ)_第9张图片

发布订阅模式的具体实现

  1. web操作查看视频
  2. 类型:fanout
  3. 特点:Fanout - 发布与订阅模式,是一种广播机制,它是没有路由 key的模式

生产者

//简单模式
public class Producer{
     
    //1.创建连接工厂
    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("10.15.0.9");
    connectionFactory.setPort(5672);
    connectionFactory.setUsername("admin");
    connectionFactory.setPassword("admin");
    connectionFactory.setVirtualHost("/");
    Connection connection = connectionFactory.newConnection("生产者");
    //2.创建通道
    Channel channel = connection.createChannel();
    //3.通过创建交换机,声明队列,绑定关系,路由key,发送消息和接受消息
    /*参数1: 是否持久化,非持久化消息会存盘吗?会存盘,但是会随着重启服务器而丢失
      参数2:是否独占队列 
      参数3:是否自动删除,随着最后一个消费者消息完毕消息以后是否把队列自动删除
  	  参数4:携带附属属性
    */
    String queueName = "queue1";
    channel.queueDeclare(queueName,false,false,false,null);
    //4.发送消息给队列queue
    /*参数1: 交换机
      参数2:队列、路由key
      参数3:消息的状态控制
  	  参数4:消息主题
    */
    //面试题:可以存在没有交换机的队列吗?不可能,虽然没有指定交换机但是一定会存在一个默认的交换机
    String message = "Hello";
    //5.准备交换机
    String exchangeName = "fanout-exchange";
    //6.定义路由key
    String routeKey = "";
    //7.指定交换机的类型
    String type = "fanout";
    channel.basicPublish(exchangeName,routeKey, null,message.getBytes());
    //8.关闭
    channel.close();
    connection.close();
}

消费者

代码一样,使用线程启动测试而已!

03:入门案例(狂神说RabbitMQ)_第10张图片

此处没有通过代码去绑定交换机和队列,而是通过可视化界面去绑定的!

RabbitMQ入门案例 - Direct 模式

//6.定义路由key
String routeKey = "email";
//7.指定交换机的类型
String type = "direct";
channel.basicPublish(exchangeName,routeKey, null,message.getBytes());

RabbitMQ入门案例 - Topic 模式

03:入门案例(狂神说RabbitMQ)_第11张图片

//6.定义路由key
String routeKey = "com.order.test.xxx";
//7.指定交换机的类型
String type = "direct";
channel.basicPublish(exchangeName,routeKey, null,message.getBytes());

代码创建及绑定

//5.准备交换机
String exchangeName = "direct_message_exchange";
String exchangeType = "direct";
//如果你用界面把queue和exchange的关系先绑定话,代码就不需要在编写这些声明代码可以让代码变得更简洁
//如果用代码的方式去声明,我们要学习一下
//6.声明交换机 所谓的持久化就是指,交换机会不会随着服务器重启造成丢失
channel.exchangeDeclare(exchangeName,exchangeType,true);

//7.声明队列
channel.queueDeclare("queue5",true,false,false,null);
channel.queueDeclare("queue6",true,false,false,null);
channel.queueDeclare("queue7",true,false,false,null);

//8.绑定队列和交换机的关系
channel.queueBind("queue5",exchangeName,"order");
channel.queueBind("queue6",exchangeName,"order");
channel.queueBind("queue7",exchangeName,"course");

channel.basicPublish(exchangeName,course, null,message.getBytes());

RabbitMQ入门案例 - Work模式

Work模式轮询模式(Round-Robin)

图解

03:入门案例(狂神说RabbitMQ)_第12张图片

当有多个消费者时,我们的消息会被哪个消费者消费呢,我们又该如何均衡消费者消费信息的多少呢?

主要有两种模式:

  1. 轮询模式的分发:一个消费者一条,按均分配
  2. 公平分发:根据消费者的消费能力进行公平分发,处理快的处理的多,处理慢的处理的少;按劳分配

生产者

跟简单模式一样!

消费者

创建两个一样的!

Work模式公平分发模式

生产者

跟简单模式一样!

消费者

//简单模式
public class Consumer{
     
	//3.接受内容
    //指标定义出来
    channel.basicQos(1);
    channel.basicConsume("queue1",false,new DefaultConsumer(){
     
        public void handle(String consumerTag, Delivery message) throws IOException {
     
          System.out.println(new String("收到消息是" + new String(meassage.getBody()),"UTF-8"));
          //改成手动应答
          channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        },new CancelCallback(){
     
            public void handle(String consumerTag) throws IOException {
     
                System.out.println("接受失败了");
        }
      });
    //4.关闭
    channel.close();
    connection.close();
}

创建两个一样的!

RabbitMQ使用场景

解耦、削峰、异步

同步异步的问题(串行)

串行方式:将订单信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端

03:入门案例(狂神说RabbitMQ)_第13张图片

public void makeOrder(){
     
    //1.发送订单
    //2.发送短信服务
    //3.发送email服务
    //4.发送app服务
}

并行方式 异步线程池

并行方式:将订单信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间

03:入门案例(狂神说RabbitMQ)_第14张图片

public void test(){
     
    //异步
    theadpool.submit(new Callable<Object>{
     
        //1.发送短信服务
    })
    //异步
    theadpool.submit(new Callable<Object>{
     
        //2.
    })
    //异步
    theadpool.submit(new Callable<Object>{
     
        //3.
    })
    //异步
    theadpool.submit(new Callable<Object>{
     
        //4.
    })
}

存在问题

  1. 耦合度高
  2. 需要自己写线程池自己维护成本太高
  3. 出现了消息可能会丢失,需要你自己做消息补偿
  4. 如何保证消息的可靠性你自己写
  5. 如果服务器承载不了,你需要自己去写高可用

异步消息队列的方式

03:入门案例(狂神说RabbitMQ)_第15张图片

好处:

  1. 完全解耦,用 MQ建立桥接
  2. 有独立的线程池和运行模型
  3. 出现了消息可能会丢失,MQ有持久化功能
  4. 如何保证消息的可靠性,死信队列和消息转移等
  5. 如果服务器承载不了,你需要自己去写高可用,HA镜像模型高可用

按照以上约定,用户的响应时间相当于是订单信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20QPS。比串行提高了3倍,比并行提高了两倍

高内聚,低耦合

03:入门案例(狂神说RabbitMQ)_第16张图片

好处:

  1. 完全解耦,用 MQ建立桥接
  2. 有独立的线程池和运行模型
  3. 出现了消息可能会丢失,MQ有持久化功能
  4. 如何保证消息的可靠性,死信队列和消息转移等
  5. 如果服务器承载不了,你需要自己去写高可用,HA镜像模型高可用

按照以上约定,用户的响应时间相当于是订单信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20QPS。比串行提高了3倍,比并行提高了两倍

高内聚,低耦合

[外链图片转存中…(img-kyL4Icya-1615906714948)]

[外链图片转存中…(img-bqSYfEx2-1615906714950)]

你可能感兴趣的:(RabbitMQ,rabbitmq)