RabbitMQ系列教程(十)ACK確認機制與消息補償

概述

在實際項目中如果業務代碼出現BUG,消費端進行消費的時候,我們可以記錄錯誤日誌,然後在消費端進行消息補償。如果出現服務器宕機問題,那就需要手工ACK,然後在生產端進行消息補償。生產端消息補償可以使用RabbitMQ的confirm機制

ACK機制與消費端消息補償機制

  • channel.basicConsume(...)方法的autoAck參數改爲false

  • channel.basicAck(long deliveryTag, boolean multiple);方法,消費成功簽收
    參數說明:
    deliveryTag:消息標識
    multiple:是否批量簽收

  • basicNack(long deliveryTag, boolean multiple, boolean requeue) ,消息消費失敗
    參數說明:
    deliveryTag:消息標識
    multiple:是否批量簽收
    requeue:true 消息會重回隊列,false 消息會進入到死信隊列

代碼演示

  • 生產端
 public static void main(String[] args) throws Exception{
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬主機
        connectionFactory.setVirtualHost("/");

        //創建一個鏈接
        Connection connection = connectionFactory.newConnection();

        //創建channel
        Channel channel = connection.createChannel();


        String exchangeName="test_ack_exchange";
        String routeKey="ack.test";
        for (int i=0;i<5;i++){

            Map<String, Object> headers = new HashMap<String, Object>();
            //演示重回隊列機制,使用num==0的消息簽收失敗重回隊列
            headers.put("num", i);
            AMQP.BasicProperties properties=new AMQP.BasicProperties().builder()
                    .deliveryMode(2)
                    .contentEncoding("UTF-8")
                    .headers(headers)
                    .build();

            String msg="RabbitMQ send message ack test!"+i;
            channel.basicPublish(exchangeName,routeKey,properties,msg.getBytes());
        }
    }
  • 消息端
public static void main(String[] args) throws  Exception{
        System.out.println("======消息接收start==========");
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬主機
        connectionFactory.setVirtualHost("/");
        //創建鏈接
        Connection connection = connectionFactory.newConnection();

        //創建channel
        Channel channel = connection.createChannel();
        String exchangeName="test_ack_exchange";
        String exchangeType="topic";
        //聲明Exchange
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        String queueName="test_ack_queue";
        //聲明隊列
        channel.queueDeclare(queueName,true,false,false,null);
        String routeKey="ack.#";
        //綁定隊列和交換機
        channel.queueBind(queueName,exchangeName,routeKey);
        /**
         * autoAck:false  設置爲手工簽收
         */
        channel.basicConsume(queueName, false, new DefaultConsumer(channel) {

                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    System.out.println("接收到消息::"+new String(body));
                    try {
                        Thread.sleep(3000); //休眠5秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //演示重回隊列機制,使用num==0的消息簽收失敗重回隊列
                    if((Integer)properties.getHeaders().get("num") == 0) {
                        /**
                         * 參數說明:1、消息標識  2、是否批量簽收  3、是否重回隊列
                         */
                        channel.basicNack(envelope.getDeliveryTag(), false, true);
                    } else {
                        channel.basicAck(envelope.getDeliveryTag(), false);
                    }


                }
            });

    }

運行代碼以上後,由於在消費端,設置了第一條消息,簽收失敗重回隊列,在RabbitMQ控制檯中我們可以看到始終有一條消息未簽收確認
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章