不公平分发:在消费者work01中,睡眠时间较短,处理消息速度很快。相反,再消费者work02中睡眠时间较长,处理速度较慢。从而导致有的消费者一直处于空闲状态。这是一种不太好的额处理方式
如何实现:消费者中设置参数channel.bascicQos(1)。信道中只允许传输一条消息,那么当这条消息处理完后,队列会立马发送下一条消息,所以这个时候快的不断处理,慢的等待当前处理完在处理下一条,这样就实现了能者多劳(所以我们给效率慢的那个消费者获取消息的信道设置,快的不用设置,不要设置错了)
public class Producer { public static final String QUEUE_NAME = "test_basic_qos"; public static final String EXCHANGE_NAME = "test_basic_qos"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.queueDeclare(QUEUE_NAME,false,false,false,null); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"basic.qos"); Scanner scanner = new Scanner(System.in); while(scanner.hasNext()) { String message = scanner.next(); System.out.println("发送消息为:" + message); channel.basicPublish(EXCHANGE_NAME,"basic.qos",null,message.getBytes(StandardCharsets.UTF_8)); } } }
public class Consumer02 { public static final String QUEUE_NAME = "test_basic_qos"; public static void main(String[] args) throws Exception { Channel channel = RabbitMqUtils.getChannel(); DeliverCallback deliverCallback = (consumerTag, message) -> { try { SleepUtils.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("高性能服务器接受:" + new String(message.getBody())); channel.basicAck(message.getEnvelope().getDeliveryTag(),false); }; CancelCallback cancelCallback = consumerTag -> {}; channel.basicConsume(QUEUE_NAME,false,deliverCallback,cancelCallback); } }
public class Consumer01 { public static final String QUEUE_NAME = "test_basic_qos"; public static void main(String[] args) throws Exception { Channel channel = RabbitMqUtils.getChannel(); channel.basicQos(1); DeliverCallback deliverCallback = (consumerTag,message) -> { try { SleepUtils.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("低性能服务器接受:" + new String(message.getBody())); channel.basicAck(message.getEnvelope().getDeliveryTag(),true); }; CancelCallback cancelCallback = consumerTag -> {}; channel.basicConsume(QUEUE_NAME,false,deliverCallback,cancelCallback); } }
预取值(perfetch) :用于定义通道上允许的未确认消息的最大数量。一旦数量达到配置的数量,RabbitMQ将停止在通道上传递更多消息,除非至少有一个未处理的消息被确认。
举例:假设在通道上有未确认的消息5,6,7,8,并且通道的预取计数为4,此时RabbtMQ将不会在该通道上再传递任何消息,除非至少有一个为应答的消息被ack。比如说tag=6这个消息刚刚被确认ack,RabbitMQ将会感知这个情况并再发一条消息,消息应答和Qos预取值对用户吞吐量有重大影响。通常,增加预取值将提高向消费者传递消息的速度,
虽然自动应答传输消息速率是最佳的,但是,在这种情况下已传递但尚未处理
的消息的数量也会增加,从而增加了消费者的
RAM
消耗
(
随机存取存储器
)
应该小心使用具有无限预处理
的自动确认模式或手动确认模式,消费者消费了大量的消息如果没有确认的话,会导致消费者连接节点的
内存消耗变大,所以找到合适的预取值是一个反复试验的过程,
perfetchCount设置为0,轮询分发,设置为1,则不公平分发,设置大于1,则是预取值。