rabbitmq学习(4)——work queue工作队列之Fair Prefetch 公平分发

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_38322527/article/details/102726113

一、出现的原由

在上一篇博客中,我们对 消费者一(1000ms)消费者二(2000ms) 设置了不同的延迟效果。运行后,却出现了两个消费者处理的消息数完全一致。
但我们从实际的项目需求来说,消费者一处理速度快,就需要多分配消息处理到消费者一中,消费者二处理慢,就少分配消息至消费者二中,这样能够提升消息处理的效率。

由此,我们能否使用一项技术,让执行效率高的多消费,执行效率低的少消费呢? ---- 公平分发 出现了。

二、实现公平分发

2.1、消息生产者

相对于简单消息队列和工作队列(轮询)而言,消息生产者需要具有限制发送消息数的功能,所以在原有的消息生产流程上,需要限定每次发送的最大消息条数。

channel.basicQos(1);

此处作为demo操作,只设置为1。这条执行语句的含义是:

在消息队列收到消息消费者发送来的“消息已消费”的消费回执信息前,不会向该消费者继续发送消息,只有收到了回执信息,才会继续向该消息消费者发送下一条消息。
例如:我有A、B、C 三个消息消费者,消息队列最初给三个消息消费者都发送了消息,A、C已经处理完毕,但B还在处理,消息队列收到A、C的回执信息,但还未收到B的回执信息,此时的消息队列会给消息消费者A、C继续发送下一条消息,但不会给B继续发送消息。

消息生产者代码:

import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import cn.linkpower.util.MqConnectUtil;

/**
 * 公平分发--谁做的快谁就多做!<br>
 * 只有在消息消费者成功消费消息,发送消费成功的指令给队列后,消息队列才会继续向该消费者发送下一条消息指令。<br>
 * @author 76519
 *
 */
public class Send {
	private static final String queue_name = "test_work_queue";
	public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
		//1、建立连接
		Connection mqConnection = MqConnectUtil.getMqConnection();
		//2、建立信道(通道)
		Channel channel = mqConnection.createChannel();
		//3、声明队列
		channel.queueDeclare(queue_name, false, false, false, null);
		
		//公平分发---
		//为了开启公平分发操作,在消息消费者发送确认收到的指示后,消息队列才会给这个消费者继续发送下一条消息。
		//此处的 1 表示 限制发送给每个消费者每次最大的消息数。
		channel.basicQos(1);
		
		//4、发送100条消息
		for (int i = 0; i < 50; i++) {
			String string = "hello xiangjiao "+i;
			System.out.println("send msg = "+string);
			//发送消息
			channel.basicPublish("", queue_name, null, string.getBytes());
			//消息发送慢一点
			Thread.sleep(i*5);
		}
		//5、使用完毕后,需要及时的关闭流应用
		channel.close();
		mqConnection.close();
	}
}

2.2、消息消费者

依旧按照之前的两个消费者区别设定,消费者处理每条消息会延迟1000ms,消费者二处理每条消息会延迟2000ms。
所以此处只写明一个消费者的代码:

import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
import cn.linkpower.util.MqConnectUtil;

/**
 * 消息消费者要实现 “公平分发” 的操作,需要关闭自动应答操作;<br>
 * 同时,在处理完消息后,需要向消息队列做“消费完成”的应答!<br>
 * @author 76519
 *
 */
public class GetMsg1 {
	private final static String queue_name="test_work_queue";
	public static void main(String[] args) throws IOException, TimeoutException {
		//1、建立连接
		Connection mqConnection = MqConnectUtil.getMqConnection();
		//2、获取信道
		final Channel channel = mqConnection.createChannel();
		//3、声明队列
		channel.queueDeclare(queue_name, false, false, false, null);
		
		//公平分发---每次只分发一个消息
		channel.basicQos(1);
		
		//4、信访室接受消息
		DefaultConsumer consumer = new DefaultConsumer(channel){
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
					throws IOException {
				String message = new String(body, "UTF-8");
				System.out.println(" get msg new1 = " + message );
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					System.out.println("get msg new1 done");
					//公平分发--- 消费完成后,需要做相关的回执信息
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		//5、创建监听
		//channel.basicConsume(queue_name,true, consumer);
		//公平分发--- 同时需要关闭自动“应答”
		channel.basicConsume(queue_name, false,consumer);
	}
}

三、运行效果测试

消费者一(1000ms):
在这里插入图片描述
消费者二(2000ms):
在这里插入图片描述

四、现象描述

两个消费者全部消费完信息后,看消费的消息数目,发现:
消费者一比消费者处理的消息要多很多!

猜你喜欢

转载自blog.csdn.net/qq_38322527/article/details/102726113