《RabbitMQ篇》消息应答和发布确认

消息应答

消息应答机制:消费者接收信息并处理完之后,告诉rabbitmq该信息已经处理,rabbitmq可以把该信息删除了.

消息自动重新入队:如果处理某个消息的消费者异常关闭了,没有发送ACK确认,rabbitmq会将其重新入队,分发给其他消费者处理。

自动应答

消息发送后即被认为传送成功。该模式弊端,消费者不断的接收消息,如果处理不及时,导致内存耗尽,系统杀死消费者进程。所以适用于消费者可以高效处理信息的情况下。

手动应答:

Channel.basicAck(long deliveryTag, boolean multiple):

确认一条或多条收到的消息。对于经过确认的消息,RabbitMQ 认为该消息成功的处理,可以将其丢弃了。

在手动应答情况下,如果消费者没有关闭,但就是不发送ACK确认,这条消息就会一直在MQ中显示unacked,不会重新分发给其他消费者。

deliveryTag:对应消息的标识。

multiple:如果为True,则应用多消息。

multiple该参数用于开启批量应答:比如说 channel 上有传送 tag 的消息 5,6,7,8 当前 tag 是 8 那么此时 5-8 的还未应答的消息都会被确认收到消息应答。

Channel.basicNack(long deliveryTag, boolean multiple, boolean requeue):

拒绝一条或多条收到的消息。

deliveryTag:对应消息的标识。

multiple:如果为True,则应用多消息。

requeue:如果为True,拒绝的消息将会重新加入队列

重新入队的消息会分发给其他消费者,不重新入队的消息将会丢失/死信。

Channel.basicReject(long deliveryTag, boolean requeue):

拒绝一条消息。与 Channel.basicNack 相比少一个参数Multiple。

发布确认

生产者把消息发送到MQ后,需要MQ返回一个ACK给生产者,这样生产者才知道自己的消息成功发出去了。

实现过程:生产者将信道设置成confirm模式,所有在该信道的消息都会被指派一个唯一的id,消息到达匹配的队列后,broker发送一个确认给生产者,这样生产者就知道消息已经发布到MQ了

RabbitMQ默认没有开启发布确认模式的,需要使用Channel.confirmSelect() 开启发布确认。

Channel.waitForCinfirms():等待Broker确认或拒绝自上次调用以来发布的所有消息。

单个发布确认

单个确认发布:发布一个确认一个,才能接着发第二个。

优缺点:可以确认哪个消息失败,适用于吞吐量不大的程序。

java 复制代码
public class ConfirmMessage {

    //消息的个数
    public static final int MESSAGE_COUNT = 1000; 

    public static void main(String[] args) throws Exception {
        publishMessageIndividually();//发布1000个单独确认消息,耗时:546ms
    }
    public static void publishMessageIndividually() throws Exception {
        Channel channel = RabbitMQUtil.getChannel();
        //队列的声明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,true,false,null);
    
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();
    
        //批量发消息
        for (int i = 1; i <= MESSAGE_COUNT; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
            //单个确认
            boolean flag = channel.waitForConfirms();
            if(flag){
                // TODO:消息发送成功的处理逻辑
            } else {
                // TODO: 消息发送失败的处理逻辑
            }
        }
        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("发布"+MESSAGE_COUNT+"个单独确认消息,耗时:"+(end-begin)+"ms");
    }
}

批量发布确认

批量发布确认:以批次发布,一批次可以有很多消息,待批次发布完,才确认。

优缺点:速度比单个快,但是不能确认哪个消息失败。

java 复制代码
public class ConfirmMessage {

    //消息的个数
    public static final int MESSAGE_COUNT = 1000; 

    public static void main(String[] args) throws Exception {
        publishMessageBatch(); //发布1000个批量确认消息,耗时:117ms
    }
    public static void publishMessageBatch() throws Exception {
        Channel channel = RabbitMQUtil.getChannel();
        //队列的声明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,true,false,null);
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();
    
        int batchSize = 10;
    
        //批量发消息
        for (int i = 1; i <= MESSAGE_COUNT; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
            //批量确认
            if(i % batchSize == 0) {
                boolean flag = channel.waitForConfirms();
                if(flag) {
                    // TODO:消息发送成功的处理逻辑
                } else {
                    // TODO: 消息发送失败的处理逻辑
                }
            }
        }
    
        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("发布"+MESSAGE_COUNT+"个批量确认消息,耗时:"+(end-begin)+"ms");
    
    }
}

异步发布确认

异步确认发布:每个信息都有自己的标识,一直发布即可,发布成功与否,都会有回调信息。

优缺点:最快,又能确认哪个消息发布失败。

java 复制代码
public class ConfirmMessage {

    //消息的个数
    public static final int MESSAGE_COUNT = 1000;

    public static void main(String[] args) throws Exception {
        publishMessageAsync(); //发布1000个异步确认消息,耗时:61ms
    }
    public static void publishMessageAsync() throws Exception {
        Channel channel = RabbitMQUtil.getChannel();
        //队列的声明
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,true,false,null);
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();

        //异步确认
        ConfirmCallback confirmAckCallback = (deliveryTag, multiple) -> {
            // TODO:消息发送成功的处理逻辑
        };
        ConfirmCallback confirmNackCallback = (deliveryTag, multiple) -> {
            // TODO: 消息发送失败的处理逻辑
        };
        channel.addConfirmListener(confirmAckCallback, confirmNackCallback);

        //批量发消息
        for (int i = 1; i <= MESSAGE_COUNT; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
        }

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("发布"+MESSAGE_COUNT+"个异步确认消息,耗时:"+(end-begin)+"ms");
    }
}

消息应答和发布确认的区别

消息应答属于消费者,消费完消息告诉MQ已经消费成功。

发布确认属于生产者,生产消息发送到MQ,MQ告诉生产者已经收到消息。

相关推荐
下地种菜小叶5 小时前
定时任务系统怎么设计?一次讲清任务注册、分布式调度、幂等执行与失败补偿
java·开发语言·数据库·oracle·rabbitmq
QC·Rex12 小时前
消息队列架构设计 - Kafka/RocketMQ/RabbitMQ 深度对比与实战
kafka·rabbitmq·rocketmq
hINs IONN1 天前
RabbitMQ HAProxy 负载均衡
rabbitmq·负载均衡·ruby
eSsO KERF2 天前
RabbitMQ之交换机
分布式·rabbitmq·ruby
Albert Edison2 天前
【RabbitMQ】Topics 通配符模式(使用案例)
分布式·rabbitmq
Ssan PRIN2 天前
深度掌握 RabbitMQ 消息确认(ACK)机制,确保消息万无一失
分布式·rabbitmq
jessecyj2 天前
【RabbitMQ】超详细Windows系统下RabbitMQ的安装配置
windows·分布式·rabbitmq
MoFe13 天前
【.net core】【RabbitMq】rabbitmq在.net core中的简单使用
分布式·rabbitmq·.netcore
何中应3 天前
在windows本地部署RabbitMQ
分布式·消息队列·rabbitmq
低客的黑调4 天前
RabbitMQ-从入门到生产落地
分布式·rabbitmq