RabbitMQ的第2种消息模型:work模式

本文深入探讨RabbitMQ的工作消息模型,解析能者多劳原则如何通过手动确认机制实现,对比自动确认与手动确认机制下消费者A与消费者B的消费结果,强调手动确认的重要性。

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

work消息模型【能者多劳】

不同消费者可能消费消息的速度不一样,work模型通过手动确认机制实现能者多劳

多个消费者通过自动确认机制
工具类

public class RabbitMQUtil {

    private static ConnectionFactory connectionFactory;
    static {
        //创建连接工厂
        connectionFactory = new ConnectionFactory();
        //设置RabbitMQ服务器所在主机ip
        connectionFactory.setHost("www.onething.top");
        //设置端口号
        connectionFactory.setPort(5672);
        //设置虚拟主机
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("123456nw");
    }

    public static Connection getConnection() {

        //创建连接对象
        try {
            return connectionFactory.newConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void closeConnectionAndChannel(Channel channel, Connection connection) {
        try {
            if(channel!=null){
                channel.close();
            }
            if(connection!=null){
                connection.close();
            }
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

工人队列消息生产者

public class WorkQueueDemo {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work", true, false, false, null);
        for (int i = 0; i < 20; i++) {
            channel.basicPublish("", "work", MessageProperties.PERSISTENT_TEXT_PLAIN, ("生产者" + i).getBytes());
        }
        RabbitMQUtil.closeConnectionAndChannel(channel,connection);
    }
}

工人队列消费者A

public class WorkQueueConsumerADemo {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work", true, false, false, null);
        channel.basicConsume("work", true,new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("consumerA:"+new String(body));
            }
        });
    }
}

工人队列消费者B

public class WorkQueueConsumerBDemo {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work", true, false, false, null);
        channel.basicConsume("work",true, new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                try {
                    Thread.sleep(1000);  // 消费者A与消费者B的区别
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("consumerB:"+new String(body));
            }
        });
    }
}

设置为自动确认机制时,消费者A与消费者B消费结果对比如下:
在这里插入图片描述
**总结:**默认情况下,RabbitMQ按顺序将消息发送给每个消费者,即使每个消费者消费者消费消息的速度不同,但每个消费者收到的消息数量相同,这种消费方式为轮询。

自动确认机制时,当消费者连接上队列,如果没有指定消费者一次获取消息的条数,所以队列把队列中的所有消息一下子推送到消费者端,当消息从队列被推出时的那一刻就表示已经对消息进行自动确认了,消息就会从队列中被标记为删除,至于消费者是否消费完已经收到的消息,就不得而知了。当消费者未处理完收到的消息时,重启RabbitMQ,此时就会出现消息丢失。因此开发过程中不建议使用自动确认机制

RabbitMQ的确认模式

参考文章:RabbitMQ消息确认机制之Confirm模式总结
(1)自动确认
只有消费者从队列中获取了消息,无论是否消费成功,都认为消息已经被消费,队列会把该消息数据删掉
(2)手动确认
消费者从队列获取消息后,MQ服务器会将该消息标记为不可用,等待消费者反馈。如果一直没有反馈,则一直未不可用状态,该消息不会被删除也不能被消费
在这里插入图片描述
当出现Unacked的消息时,只需要断开连接或重启RabbitMQ,被标记Unacked状态的消息就会重新变为Ready状态

public class WorkQueueConsumerADemo {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        /**
         * 每次只能消费一个消息【切记这里需要设置】
         */
        channel.basicQos(1);
        channel.queueDeclare("work", true, false, false, null);
        /**
         * 第1个参数:队列名
         * 第2个参数:自动确认
         * 第3个参数:回调方法,用于处理消息
         */
        channel.basicConsume("work", false, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("consumerA:" + new String(body));
                /**
                 * 手动确认
                 * 第1个参数:通过发送Tag标识来确认消费的是消息队列中的哪个消息
                 * 第2个参数:是否开启多个消息同时确认,这里我们设置了每次只能消费一个消息,因此不需要开启
                 */
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        });
    }
}
public class WorkQueueConsumerBDemo {
    public static void main(String[] args) throws IOException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        /**
         * 每次只能消费一个消息【切记这里需要设置】
         */
        channel.basicQos(1);
        channel.queueDeclare("work", true, false, false, null);
        /**
         * 第1个参数:队列名
         * 第2个参数:自动确认
         * 第3个参数:回调方法,用于处理消息
         */
        channel.basicConsume("work", false, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
                System.out.println("consumerA:" + new String(body));
                /**
                 * 手动确认
                 * 第1个参数:通过发送Tag标识来确认消费的是消息队列中的哪个消息
                 * 第2个参数:是否开启多个消息同时确认,这里我们设置了每次只能消费一个消息,因此不需要开启
                 */
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        });
    }
}

设置为手动确认机制后,消费者A与消费者B消费结果对比如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值