二、RabbitMQ——消息分发机制

我们知道每个消息的处理时间是不同的,换句话说消息的复杂度是不同的,有些消息很复杂,需要很久的时间,有些消息很简单,只需耗时一会就可以完成,而在实际情况下如何分配资源,让效率达到最大化,从而实现按能力分配任务,达到物尽其用。这就需要消息的分发机制。

一、Fair dispatch(公平分发)

这里我们创建DistributionSender.java和DistributionReceiver.java来模拟发送者和接收者。
DistributionSender.java

@Component
public class DistributionSender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send(int i) {
        // 发送的消息
        String message = "This is a task, and the complexity is " + i + "。" + StringUtils.repeat(".", i);
        this.rabbitTemplate.convertAndSend("distribu", message);
    }
}

使用默认交换机,队列为“distribu”

    /**
     * 申明distribu队列
     * 
     * @return
     */
    @Bean
    public Queue DistribuQueue() {
        return new Queue("distribu");
    }

java和DistributionReceiver.java

@Component
public class DistributionReceiver {


    /**
     * 消费者A
     * 
     * @param msg
     */
    @SuppressWarnings("deprecation")
    @RabbitListener(queues = "distribu")
    public void processA(Message message) {
        String msg = new String(message.getBody());
        System.out.println(" DistributionReceiverA  : " + msg);
        SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSS");
        System.out.println(" ProccessingA... at " + time.format(new Date()));

        try {
            for (char ch : msg.toCharArray()) {
                if (ch == '.') {
                    doWork(1000);
                }
            }
        } catch (InterruptedException e) {
        } finally {
            System.out.println(" A Done! at " + time.format(new Date()));
        }
    }

    private void doWork(long time) throws InterruptedException {
        Thread.sleep(time);
    }

}

添加RabbitTest.java文件模拟请求

@Controller
public class RabbitTest{

    @Autowired
    private DistributionSender distributionSender;

    /**
     * 分发机制消息发送测试
     */
    @GetMapping("/distribu")
    public void distribu() {
        distributionSender.send(3);
    }
}

运行程序,访问http://localhost:8080/rabbit/...,可以得到下面的打印的信息:

 DistributionReceiverA  : This is a task, and the complexity is 3。...
 ProccessingA... at 2018-05-23 21:29:18:0628
 A Done! at 2018-05-23 21:29:21:0639

从打印的信息可以看出这里就模拟了完成任务需要3秒钟的时间任务实现。

下面我们更改发送的消息数量,在controller控制器里面进行更改,如下:

    /**
     * 分发机制消息发送测试
     */
    @GetMapping("/distribu")
    public void distribu() {
        for (int i = 0; i < 5; i++) {
            //发送任务复杂度都为1的消息
            distributionSender.send(1);
        }
    }

模拟发送5条消息,并且每条发送的消息的复杂度都是相同的,复杂度都为1。

然后再在receiver包中DistributionReceiver.java新增一个消费者B,如下:

/**
     * 消费者B
     * 
     * @param msg
     */
    @SuppressWarnings("deprecation")
    @RabbitListener(queues = "distribu")
    public void processB(Message message) {
        String msg = new String(message.getBody());
        System.out.println(" DistributionReceiverB  : " + msg);
        SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSS");
        System.out.println(" ProccessingB... at " + time.format(new Date()));

        try {
            for (char ch : msg.toCharArray()) {
                if (ch == '.') {
                    doWork(1000);
                }
            }
        } catch (InterruptedException e) {
        } finally {
            System.out.println(" B Done! at " + time.format(new Date()));
        }
    }

再次运行程序,访问接口,结果如下:

 DistributionReceiverA  : This is a task, and the complexity is 1。.
 ProccessingA... at 2018-05-22 23:23:43:0014
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:23:43:0014
 A Done! at 2018-05-22 23:23:44:0017
 B Done! at 2018-05-22 23:23:44:0017
 DistributionReceiverA  : This is a task, and the complexity is 1。.
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingA... at 2018-05-22 23:23:44:0093
 ProccessingB... at 2018-05-22 23:23:44:0093
 A Done! at 2018-05-22 23:23:45:0095
 B Done! at 2018-05-22 23:23:45:0095
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:23:45:0143
 B Done! at 2018-05-22 23:23:46:0148

在消息相同,A、B处理能力一样情况下,我们可以发现A、B几乎是同时处理消息,消息发送顺序为A->B->A->B->B。可以看出这里并没有实现A与B平均轮询的情况,在最后的情况B执行了两次。

接着现在我们把A处理能力更改为每个点要Thread.sleep(4000), B为Thread.sleep(1000),就是B的处理能力是A的四倍。运行一下,我们看一下打印的结果:

DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:24:48:0623
 DistributionReceiverA  : This is a task, and the complexity is 1。.
 ProccessingA... at 2018-05-22 23:24:48:0623
 B Done! at 2018-05-22 23:24:49:0624
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:24:49:0663
 B Done! at 2018-05-22 23:24:50:0664
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:24:50:0704
 B Done! at 2018-05-22 23:24:51:0709
 DistributionReceiverB  : This is a task, and the complexity is 1。.
 ProccessingB... at 2018-05-22 23:24:51:0748
 A Done! at 2018-05-22 23:24:52:0629
 B Done! at 2018-05-22 23:24:52:0749

现在我们可以清晰地看到在这里B处理了4条消息,而A只处理了1条消息。这里就是按公平分发的机制来发送消息的,即按消费者处理能力来分发消息。
这就是公平分发。

二、Round-robin dispatch(轮询分发)

相较于公平分发而言,轮询分发即不去判断消费者的处理速率,也不考虑每个任务的时长,按照轮流排序的方式,把任务逐个发给消费者,并且是提前一次性分配,并非一个一个分配。

你可能感兴趣的:(rabbitmq)