RabbitMQ公平队列原理和使用

本文介绍了RabbitMQ公平队列的工作原理,针对消费者处理任务速度不均的问题,通过设置`basicQos`参数为`1`,确保每个消费者在处理完当前消息并确认后才会收到新的消息,从而实现负载均衡。这种方式使得处理速度快的消费者能够处理更多的消息,提高整体效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RabbitMQ公平队列原理和使用

 目前消息转发机制是平均分配,这样就会出现俩个消费者,奇数的任务很耗时,偶数的任何工作量很小,造成的原因就是近当消息到达队列进行转发消息。并不在乎有多少任务消费者并未传递一个应答给RabbitMQ。仅仅盲目转发所有的奇数给一个消费者,偶数给另一个消费者。

为了解决这样的问题,我们可以使用basicQos方法,传递参数为prefetchCount= 1。这样告诉RabbitMQ不要在同一时间给一个消费者超过一条消息
换句话说,只有在 消费者空闲的时候会发送下一条信息。调度分发消息的方式,也就是告诉RabbitMQ每次只给消费者处理一条消息,也就是等待消费者处理完毕并自己对刚刚处理的消息进行确认之后,才发送下一条消息,防止消费者太过于忙碌,也防止它太过去清闲。
通过 设置channel.basicQos(1);

  服务器能力不同,能者多劳。 均摊模式的话,都处理相同数量的

 消息队列 发出去的消息被消费完了 然后收到 ack包 才可以继续发给他

 公平队列原理:队列服务器向消费者发送消息的时候,消费者采用手动应答模式,队列服务器必须要收到消费者发送ack结果通知,才会发送下一个消息。(快的处理的多,消费的多)

producer:

package com.toov5.Producer;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.toov5.utils.MQConnectionUtils;

public class Producer {
    // 队列名称
    private static final String UEUE_NAME = "test_queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建新的连接
        Connection connection = MQConnectionUtils.newConnection();
        // 创建Channel
        Channel channel = connection.createChannel();
        // 创建队列
        channel.queueDeclare(UEUE_NAME, false, false, false, null);
        channel.basicQos(1); // 保证 取一个消费  队列给消费者发送消息时候 一个消息
        for (int i = 0; i < 10; i++) {
            // 创建message
            String msg = "toov5_message";
            System.out.println("生产者投递消息" + msg + i);
            // 生产者发送消息
            channel.basicPublish("", UEUE_NAME, null, msg.getBytes());
        }
        // 关闭通道和连接
        channel.close();
        connection.close();

    }
}

 

Consumer1

package com.toov5.Consumer;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.toov5.utils.MQConnectionUtils;

public class Consumer1 {
  
     //队列名称
        private static final String QUEUE_NAME = "test_queue";
        
        public static void main(String[] args) throws IOException, TimeoutException {
            System.out.println("消费者启动..........1");
            //创建新的连接
        Connection connection = MQConnectionUtils.newConnection();
           //创建Channel
            final Channel channel = connection.createChannel();
            // 消费者关联队列
             channel.queueDeclare(QUEUE_NAME, false, false, false, null);
             channel.basicQos(1);
              DefaultConsumer defaultConsumerr = new DefaultConsumer(channel) {
                  //监听获取消息
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
                            byte[] body) throws IOException {
                        String msg =new String(body,"UTF-8");
                        System.out.println("消费者获取生产者消息:"+msg);
                        try {
                            //模拟应答等待时间
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            
                        }finally {
                           channel.basicAck(envelope.getDeliveryTag(), false);  //手动应答 告诉消息队列服务器 消费成功
                        }
                    }
              };
            //牵手模式设置  默认自动应答模式  true:自动应答模式  
              channel.basicConsume(QUEUE_NAME, false, defaultConsumerr);//    fanse手动应答          

        }
}

 

Consumer2

package com.toov5.Consumer;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.toov5.utils.MQConnectionUtils;

public class Consumer2 {
  
     //队列名称
        private static final String QUEUE_NAME = "test_queue";
        
        public static void main(String[] args) throws IOException, TimeoutException {
            System.out.println("消费者启动..........2");
            //创建新的连接
        Connection connection = MQConnectionUtils.newConnection();
           //创建Channel
            final Channel channel = connection.createChannel();
            // 消费者关联队列
             channel.queueDeclare(QUEUE_NAME, false, false, false, null);
              channel.basicQos(1);
              DefaultConsumer defaultConsumerr = new DefaultConsumer(channel) {
                  //监听获取消息
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties,
                            byte[] body) throws IOException {
                        String msg =new String(body,"UTF-8");
                        System.out.println("消费者获取生产者消息:"+msg);
                        try {
                            //模拟应答等待时间
                            Thread.sleep(300);
                        } catch (Exception e) {
                            
                        }finally {
                        channel.basicAck(envelope.getDeliveryTag(), false);  //手动应答 告诉消息队列服务器 消费成功
                        }
                    }
              };
            //牵手模式设置  默认自动应答模式  true:自动应答模式  
              channel.basicConsume(QUEUE_NAME, false, defaultConsumerr);//    fanse手动应答          
        }
}

运行结果:

睡眠少的(执行快的) 指定的多

 注意 每个消费者 必须要应答 一下! 队列服务器没有收到应答 就不会发送下一个给消费者~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值