RabbitMQ

1、RabbitMQ 简介

  MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。

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

  RabbitMQ 是一个消息代理。主要的原理就是通过接受和转发消息。RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,消息中间件主要用于组件之间的解耦。

  RabbitMQ服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。

2、使用场景

     例如:应用程序A向应用程序B发送请求并期望得到响应

              发送方(应用程序A)向消息中间件(RabbitMQ) 发送请求,接受方(应用程序B)订阅请求。发送方将消息发送给消息中间件后,异步执行程序。

              发送方(应用程序B)消息中间件(RabbitMQ) 发送请求接受方(应用程序A)订阅请求。发送方将消息发送给消息中间件后,异步执行程序。

 

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

3、RabbitMQ的优势

       高并发;负载均衡;消息持久;耦合低;响应速度快;

4、RabiitMQ术语

       Connection: 是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。

       ConnectionFactory:Connection的制造工厂。

       Channel:是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。

几个基本概念:

  (1)生产者:生产过程就像发送过程,发送消息的程序就是一个生产者,我们使用“P”来描述它。

          

  (2)消费者:消费过程与接收相似,一个消费者通常是一个等着接受消息的程序,我们使用"C"来描述。
         
  (3)Queue:(队列)是RabbitMQ的内部对象,用于存储消息,用下图表示。
       
  (4)Exchange:(交换机)用下图表示。
           
     (5)Routing key:

                用于绑定交换机与队列间的key。

                生产者发送消息给交换机时,一般都会指定routing key,用于绑定交换机与队列。

                这还跟交换机类型(Exchange Type)有关:

                四种类型,fanout,direct,topic,headers 

  图解分析:

  生成者生产消息,发送消息到队列,消费者可以从队列获取消息并消费。

          

  多个消费者订阅同一个队列,消息平摊:

          
   

      实际情况:生产者投递消息永远只会先经过交换机,交换机根据交换机类型或规则路由到队列。

          

     

       如果没有路由匹配到队列,则消息会丢失。

 5、RabbitMQ交换机

      1、RabbitMQ消息模型中核心的思想是生产者从不直接将消息发送给队列。实际上,生产者常常甚至不知道是否一个消息会被传递到队列中。

      2、生产者是将消息投递给交换机,消息将被发送到一个队列中还是对个队列中亦或是被抛弃,这都是交换机的类型决定的。

     

    

     交换机类型: direct,topic,deaders,fanout
    
     匿名交换机

                     RabbitMQ服务器中存在一个匿名交换机,他不能被删除之前的代码中“”即为匿名交换机

                     channel.basicPublish("", "hello", null, message.getBytes());

   

     临时队列:

                   当我们使用无参数调用queueDeclare()方法,我们创建一个自动产生的名字,不持久化,独占的,自动删除的队列。

                   String queueName = channel.queueDeclare().getQueue();//名字随机

     绑定:

                 

                1)funout类型的交换机

                  即为交换机与队列绑定,假设一个funout类型的交换机。

                  channel.queueBind(queueName, "logs", "");

             

                 Fanout类型发给所有它所知道的队列。

                channel.exchangeDeclare(“logs”, “fanout”);//声明fanout类型的队列

               2)direct类型的交换机

                     当我们需要对日志系统做严格过滤规则时。比如由于电脑磁盘有限,日志系统只对error级别的日志做保存。显然用Fanout类型交换机满足不了要求。

                     

              3)topic类型的交换机

                  更灵活,选择性更高。通配符式交换机。

      * (星标) 能替代任意一个单词。

      # (哈希) 能代替零个或多个单词。

                          

 6、使用流程

  (1)客户端连接到消息队列服务器,打开一个channel。
  (2)客户端声明一个exchange,并设置相关属性。
  (3)客户端声明一个queue,并设置相关属性。
  (4)客户端使用routing key,在exchange和queue之间建立好绑定关系。
  (5)客户端投递消息到exchange。exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。
  
      图例:
           
 

     7、代码实例

 

(1)生产者发送消息:

 1 //1、创建一个服务器连接
 2  ConnectionFactory factory = new ConnectionFactory();
 3  factory.setHost(“localhost”); //可连远程主机IP
 4  factory.setPort(5672);//固定端口
 5  factory.setUsername(“guest”);//远程必须新建用户
 6  factory.setPassword(“guest”);//密码
 7  Connection connection =  factory.newConnection(); 
 8  Channel channel = connection.createChannel();
 9 //2、生产者发布消息
10  channel.queueDeclare(“hello”, false, false, false, null); //声明队列
11  String message = "Hello World!"; 
12  channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); //发布
13 //3、关闭连接
14  channel.close();
15  connection.close();

 

(2)消费者接收消息

 1 //1、首先创建连接,与生产者一样
 2  channel.queueDeclare(“hello”, false, false, false, null); //声明队列
 3  QueueingConsumer consumer = new QueueingConsumer(channel);
 4  channel.basicConsume(QUEUE_NAME, true, consumer);
 5 //2、接收消息
 6 while (true) { 
 7 //3、线程阻塞,挂起直到队列传输消息到来
 8   QueueingConsumer.Delivery delivery = consumer.nextDelivery(); 
 9   String message = new String(delivery.getBody()); 
10 }

 

posted @ 2016-04-01 10:54  浮生若云  阅读(416)  评论(0编辑  收藏  举报