RabbitMQ:消息应答

76 阅读2分钟

消息应答

如果一段时间一个消费者出路一个长的任务只完成了一部分突然它挂掉了 概念:消费者在接到消息并处理该消息之后,告诉RabbitMQ它已经处理好了,RabbitMQ可以把该消息删除

自动应答

在高吞吐量和数据传输安全性方面,容易接受大量消息而无法处理,导致内存耗尽,消费者线程被操作系统杀死 仅适用于消费者可以高效并以某种速率处理这些消息时使用

注:自动应答不在乎消费者对消息处理是否成功,都会告诉队列删除消息。如果处理消息失败,实现自动补偿(队列投递过去 重新处理)。

手动应答

消费者处理完业务逻辑,手动返回ack(通知)告诉队列处理完了,队列进而删除消息

//用于肯定确认,RabbitMQ已经知道该消息并成功的处理该消息,可以将其丢弃
Channel.basicAck
​
//用于否定确认,
Channle.basicNack
​
//用于否定确认,比Channle.basicNack多一个参数multiple,用于是否批量处理
Channel.basicReject

multiple 批量应答

手动应答的好处就是批量应答 channe上有传送tag的消息,5、6、7、8,当前tag是8那么5-8的这些未应答的消息都会被确认收到消息应答(大概不作处理了),反之只有8(先进先出)

消息手动应答代码

生产者代码

public class Prouders{
    //队列名
    public static final String QUEUE_NAME = "ack_queue"
​
    //发消息
    public static main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        Scanner scanner = new Scanner(system.in);
        //是否有下一个消息
        while(scanner.hasNext()) {
            String message = scanner.next();
            channel.basicPublish("", QUEUE_NAME, null, message,getBytes("UTF-8"));
            System.out.println("生产发发出消息:" + message);
        }
    }

沉睡延迟工具类

public class SleepUtils {
    public static void sleep(int second){
        try {
            Thread.sleep(1000 * second);
        } catch (InterruptedException _ignored) {
            Thread.currentThread().interrupt();
        }
    }
}

消费者代码

public class Consumers_X{
    //队列名
    public static final String QUEUE_NAME = "hello"
    //接受消息
    public static main(String[] args) throws Exception{
    
        Channel channel = RabbitMQUtils.getChannel();
        System.out.println("X等待接受消息");//X是第几个进程
        
        //声明接口(lambal表达式)
        //接受消息
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            //用沉睡来模拟处理消息的时间,来做出处理能力不一样的消费者,X可自由设置
            SleepUtils.sleep(X);
            //设置UTF-8防止中文乱码
            System.out.println("接受到的消息" + new String(message.getBody(), "UTF-8"));
            //手动应答
            /**
              *1.消息标记(那个消息)
              *2.是否批量应答 
             */
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
        };
        //取消消息的回调
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消息消费被中断");
        };
        /**
          *消费者消费消息
          *1.消费那个队列
          *2.(autoAck)消费成功是否要自动应答
          *3.消费者成功消费的回调
          *4.消费者未成功消费的回调
        */
        channel.basicConsume(QUEUE_NAME, false, deliverCallback, cancelCallback);
    }
}

消息自动重新入队

消费者失去连接,导致消息未发送ACK确认,RabbitMQ了解到消息未完全处理,将其重新排队