【RabbitMQ】异步任务

一、前言

     上一篇博客介绍了用线程池实现异步任务。这一篇博客谈一谈用MQ实现异步任务。MQ的产品有灰常多,像什么MSMQ、activeMQ、RocketMQ、RabbitMQ、kafak等。在此之前先谈一谈对消息队列的理解。

二、MQ

       MQ是一种应用程序对应用程序的通讯方法,应用程序通过读写出入队列的消息来进行通信,两者无需建立连接,发布者和消费者无需知道对方的存在。

      MQ是生产者--消费者模型的一个代表,一端往消息队列中不断写入消息,而另一端则可以不断读取或订阅队列中的消息。

      使用场景:

      1、异步处理:在项目中将一些无需及时返回且耗时的操作提取出来,进行异步处理,采用异步处理,将大大节省了服务器的请求响应时间,从而提高了系统的吞吐量。

       2、消息推送

三、RabbitMQ特点

       RabbitMQ是一个由Erlang语言开发的AMQP的开源实现。

       RabbitMQ的特点为:

       1、可靠性

       RabbitMQ提供了多种技术可以让你在性能和可靠性之间进行权衡,如持久性、传输确认、投递确认。

       2、灵活的路由

       在消息进行队列之前,通过Exchange来路由消息。对于典型的路由功能,RabbitMQ已经提供了一些内置的Exchange来实现,针对更复杂的路由功能,可以将多个Exchange绑定在一起,也可以通过插件机制来实现自己的Exchange。

       3、消息集群

        多个RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。

       4、高可用

       在同一集群中队列可以被镜像到多台机器,使得在部分节点出现问题的情况下,队列仍然可用。

       5、多协议

       RabbitMQ支持多种消息队列协议。

       6、多语言客户端

       支持java、.NET、Ruby等

       7、管理界面

        RabbitMQ提供了一个易用的用户界面,用户可以监控和管理Broker的许多方面。

       8、跟踪机制

        如果消息异常,RabbitMQ提供了消息跟踪机制,使用者可以找出发生了什么。

       9、插件机制

        RabbitMQ提供了很多插件,来从多方面进行扩展,也可以编写各种插件。

四、RabbitMQ中的概念模型

  •  消息抽象模型

       消费者订阅某个队列,生产者创建消息,然后发布到队列中,最后将消息发送到监听的消费者。

        


  • RabbitMQ的基本概念

   上图是一个最简单的抽象模型,接下来将展示一个更加详细的模型。RabbitMQ内部结构如下:

   

   1、Message

    Message由消息头和消息体组成,消息体是不透明的,消息头是由一些属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

   2、Publisher

    消息的生产者,也是一个向交换机发布消息的客户端应用程序。

   3、Exchange

    用来接收生产者发送的消息,并按照一定的规则将这些消息路由给服务器中的队列。

   4、Binding

    绑定,用于消息队列和交换器之间的路由关联,一个绑定就是将交换器和队列连接起来的路由规则。

   5、Queue

   用来保存消息直到发送给消费者,它是消息的容器,1个消息可投入一个到多个队列,消息一直在队列里,等待消费者取走。

   6、Connection

    网络连接,比如一个TCP连接。

   7、Channel

    信道,或者称之为管道,是一条双向数据流通道,AMQP都是通过信道发出去的,不管是发布消息,订阅队列,还是接受消息,这些动作都是通过信道来完成的。

    8、Consumer

    消息的消费者,表示一个从消息队列中取的消息的客户端应用程序。

    9、Virtual Host

    表示一批交换器、消息队列和相关对象。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

    10、Broker

     表示RabbitMQ服务器实体

五、入门Demo

      pom文件添加依赖

    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>4.3.0</version>
    </dependency>

    <dependency>
      <groupId>com.github.sstone</groupId>
      <artifactId>amqp-client_2.10</artifactId>
      <version>1.3</version>
    </dependency>

1、Publisher

public class Publisher {
    //队列名称
    private final static String QUEUE_NAME = "Queue";
    public static void main(String[] args) {
        // 创建连接工厂
        ConnectionFactory factory = null;
        // 建立到代理服务器到连接
        Connection connection = null;
        // 获得通道
        Channel channel = null;
        try {
            factory = new ConnectionFactory();
            //设置用户名和密码
            factory.setUsername("guest");
            factory.setPassword("guest");
            // 设置 RabbitMQ 地址
            factory.setHost("localhost");
            // 建立到代理服务器到连接
            connection = factory.newConnection();
            channel = connection.createChannel();
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            String message = "hello world,hello world";
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
            System.out.println("发送  message[" + message + "] to "+ QUEUE_NAME +" success!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            try {
// 关闭资源
                channel.close();
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }
    }
}

2、consumer

public class Consumer {
    //队列名称
    private final static String QUEUE_NAME = "Queue";
    public static void main(String[] args) {
        // 创建连接工厂
        ConnectionFactory factory = null;
        // 建立到代理服务器到连接
        Connection connection = null;
        // 获得通道
        Channel channel = null;
        try {
            factory = new ConnectionFactory();
            factory.setUsername("guest");
            factory.setPassword("guest");
            factory.setHost("localhost");
            // 建立到代理服务器到连接
            connection = factory.newConnection();
            channel = connection.createChannel();
            // 1.队列名2.是否持久化,3是否局限与链接,4不再使用是否删除,5其他的属性
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            // 声明一个消费者,配置好获取消息的方式
            QueueingConsumer consumer = new QueueingConsumer(channel);
            channel.basicConsume(QUEUE_NAME, true, consumer);
            // 循环获取消息
            while (true) {
            // 循环获取信息
            // 指向下一个消息,如果没有会一直阻塞
                Delivery delivery = consumer.nextDelivery();
                String msg = new String(delivery.getBody());
                System.out.println("接收 message[" + msg + "] from " + QUEUE_NAME);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (ShutdownSignalException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
            // 关闭资源
                channel.close();
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }
    }
}

效果图如下:

猜你喜欢

转载自blog.csdn.net/qq_26545305/article/details/80378031