RabbitMQ 三 Round-robin轮询分发

在上一节中我写了一个简单队列,由于简单队列不能满足现在的需要,所以要继续学习更深的知识

由于我们上一节做了一个简单队列,他有很多缺点,比如耦合性高,生产者一一对应消费者(如果我想有多个消费者消费消息,这个时候就不行了),队列名变更,这个时候生产者与消费者要同时变更。
workqueueus工作队列

模型

RabbitMQ 三 Round-robin轮询分发_第1张图片
这个图的意思就是一个生产者把消息生产到队列中,两个消费者去消费他,甚至多个消费者消费他
Simple队列是一一对应的,在实际的开发中,生产者发送消息是毫不费力的,消费者一般是要和业务逻辑相结合的,这个时候消费者接受到消息后就需要处理,可能需要花费时间,这个时候队列就会挤压很多消息,既然这样就会出现多个消费者消费消息。


下面我们修上代码
首先是生产者

public class Send {


    private static final String QUEUE_NAME="test_work_queue";

    /**                  |----C1
     *   P-----Queue-----|
     *                   |----C2
     * @param s
     */
    public static void main(String[] s) {
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
           Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false, false,false , null);

           //发送消息
           for(int i = 0;i < 50; i++){

               String msg = "hello" + i;

               channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
               System.out.println("生产者发送的消息:"+msg);
               Thread.sleep(i*20);
           }

           channel.close();
           connection.close();
       }catch (IOException e){
           e.printStackTrace();
       }catch (TimeoutException e){
           e.printStackTrace();
       }catch(Exception e){
           e.printStackTrace();
       }
    }
}

接下来是消费者

public class Recv {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] s){
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
           Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false,false , false, null);

           //定义一个消费者
           Consumer consumer = new DefaultConsumer(channel){
               //队列中有消息就触发这个方法。
               @Override
               public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String msg = new String(body,"UTF-8");
                    System.out.println("Recv1:"+msg);
                   try {
                       Thread.sleep(2000);
                   }catch (Exception e){
                       e.printStackTrace();
                   }
               }
           };
            channel.basicConsume(QUEUE_NAME, true, consumer);

       }catch(Exception e){
           e.printStackTrace();
       }
    }
}

然后是另一个消费者

public class Recv2 {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] s){
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
           Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false,false , false, null);

           //定义一个消费者
           Consumer consumer = new DefaultConsumer(channel){
               //队列中有消息就触发这个方法。
               @Override
               public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String msg = new String(body,"UTF-8");
                    System.out.println("Recv2:"+msg);
                   try {
                       Thread.sleep(1000);
                   }catch (Exception e){
                       e.printStackTrace();
                   }
               }
           };
            channel.basicConsume(QUEUE_NAME, true, consumer);

       }catch(Exception e){
           e.printStackTrace();
       }
    }
}

首相需要声明一下,我消费者一和消费者二是消费同一个队列的,但是消费者1消费完一个要2秒,消费者2消费完一个要1秒,按理说能者多劳,消费者二要消费的更多一点,但是事实是这样么。
我们看消费结果:
消费者一的结果(由于太多,这里只截取部分):

Recv1:hello0
Recv1:hello2
Recv1:hello4
Recv1:hello6
Recv1:hello8
Recv1:hello10
Recv1:hello12

消费者二的结果:

Recv2:hello1
Recv2:hello3
Recv2:hello5
Recv2:hello7
Recv2:hello9
Recv2:hello11
Recv2:hello13

可以看出,他们是轮询消费,也就是说你消费一个,我消费一个,不会说我消费的快我消费的就多。

下面我们来说一下能者多劳的方式

这里说的能者多劳值得就是消费者一和消费者二都在消费,但是分谁的能力强,消费能力强的可以继续消费,消费能力弱的就要比消费能力消费能力强的差一些。他的原理如下图
RabbitMQ 三 Round-robin轮询分发_第2张图片
下面直接上代码
下面是生产者

 public static void main(String[] s) {
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
           Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false, false,false , null);

           //每个消费者 发送消息确认之前,消息队列不发送下一个消息到消费者,一次只处理一个消息
           //限制发送给同一个消费者 不得超过一条。
           int prefetchCount = 1;
           channel.basicQos(prefetchCount);

           //发送消息
           for(int i = 0;i < 50; i++){

               String msg = "hello" + i;

               channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
               System.out.println("生产者发送的消息:"+msg);
               Thread.sleep(i*2);
           }

           channel.close();
           connection.close();
       }catch (IOException e){
           e.printStackTrace();
       }catch (TimeoutException e){
           e.printStackTrace();
       }catch(Exception e){
           e.printStackTrace();
       }
    }

下面是消费者

public static void main(String[] s){
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
           final Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false,false , false, null);

           channel.basicQos(1);

           //定义一个消费者
           Consumer consumer = new DefaultConsumer(channel){
               //队列中有消息就触发这个方法。
               @Override
               public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String msg = new String(body,"UTF-8");
                    System.out.println("Recv1:"+msg);
                   try {
                       Thread.sleep(2000);
                   }catch (Exception e){
                       e.printStackTrace();
                   }
                   channel.basicAck(envelope.getDeliveryTag(), false);
               }
           };
           //自动应答改为false
            Boolean autoAck = false;
            channel.basicConsume(QUEUE_NAME, autoAck, consumer);

       }catch(Exception e){
           e.printStackTrace();
       }
    }

下面是另一个消费者

public static void main(String[] s){
       try{
           //获取连接
           Connection connection = ConnectionUtil.getConnection();

           //获取通道
          final Channel channel = connection.createChannel();

           //声明队列
           channel.queueDeclare(QUEUE_NAME, false,false , false, null);

           channel.basicQos(1);
           //定义一个消费者
           Consumer consumer = new DefaultConsumer(channel){
               //队列中有消息就触发这个方法。
               @Override
               public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String msg = new String(body,"UTF-8");
                    System.out.println("Recv2:"+msg);
                   try {
                       Thread.sleep(1000);
                   }catch (Exception e){
                       e.printStackTrace();
                   }
                   channel.basicAck(envelope.getDeliveryTag(), false);
               }
           };
           Boolean autoAck = false;
            channel.basicConsume(QUEUE_NAME, autoAck, consumer);

       }catch(Exception e){
           e.printStackTrace();
       }
    }

从结果看来,消费者2处理的要比消费者1多,证明我们上面的代码是没有问题的。

你可能感兴趣的:(RabbitMQ)