版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
一、出现的原由
在上一篇博客中,我们对 消费者一(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):
四、现象描述
两个消费者全部消费完信息后,看消费的消息数目,发现:
消费者一比消费者处理的消息要多很多!