在之前的工作队列模式中,对于多个消费者,也就是多个工作线程采用的是轮训分发的方式消费消息。
轮训分发策略并不是很好,比如两个消费者在处理任务时候,其中一个消费者处理速度快,另一个消费者处理速度慢。采用轮训分发就会造成处理速度快的消费者有很大一部分时间处于空闲状态。应该遵循能者多劳的原则。
不公平分发
设置参数 channel.basicQos(1); 1表示不公平分发。0表示轮训分发,默认值。
这个参数应该设置在消费方,由消费方决定是否使用非公平分发。
package com.xkj.org.mq.ack;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.xkj.org.utils.RabbitMQUtil;
import java.io.IOException;
public class Worker01 {
private static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws IOException {
Channel channel = RabbitMQUtil.getChannel();
//设置不公平分发
channel.basicQos(1);
DeliverCallback deliverCallback = (consumerTag, message) -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("接受到消息:"+ new String(message.getBody(), "UTF-8"));
//第一个参数,消息标记tag
//第二个参数,false非批量应答
channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
};
CancelCallback cancelCallback = consumerTag -> {
System.out.println("work1 消息消费被中断");
};
System.out.println("worker1等待1s接收消息.......");
//设置手动应答
channel.basicConsume(QUEUE_NAME, false, deliverCallback, cancelCallback);
}
}
预取值
指定每个消费者取多少条消息。
prefetch代表信道channel中放的消息数量。
channel.basicQos(prefetch), prefetch值为0表示轮训分发,1表示非公平分发,如果>1表示预期值prefetch。
设置在消费者端,消费者A预期值2条,消费者B预取值5条,生产者发送7条消息。表示的是消息堆积在信道里的数量。
package com.xkj.org.mq.ack;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.xkj.org.utils.RabbitMQUtil;
import java.io.IOException;
public class Worker01 {
private static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws IOException {
Channel channel = RabbitMQUtil.getChannel();
//设置不公平分发,预期值2
channel.basicQos(2);
DeliverCallback deliverCallback = (consumerTag, message) -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("接受到消息:"+ new String(message.getBody(), "UTF-8"));
//第一个参数,消息标记tag
//第二个参数,false非批量应答
channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
};
CancelCallback cancelCallback = consumerTag -> {
System.out.println("work1 消息消费被中断");
};
System.out.println("worker1等待1s接收消息.......");
//设置手动应答
channel.basicConsume(QUEUE_NAME, false, deliverCallback, cancelCallback);
}
}
package com.xkj.org.mq.ack;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.xkj.org.utils.RabbitMQUtil;
import java.io.IOException;
public class Worker02 {
private static final String QUEUE_NAME = "ack_queue";
public static void main(String[] args) throws IOException {
Channel channel = RabbitMQUtil.getChannel();
//预期值5
channel.basicQos(5);
DeliverCallback deliverCallback = (consumerTag, message) -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("接受到消息:"+ new String(message.getBody(), "UTF-8"));
//第一个参数,消息标记tag
//第二个参数,false非批量应答
channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
};
CancelCallback cancelCallback = consumerTag -> {
System.out.println("work2 消息消费被中断");
};
System.out.println("worker2等待30s接收消息.......");
//设置手动应答
channel.basicConsume(QUEUE_NAME, false, deliverCallback, cancelCallback);
}
}