Rabbitmq message publishing confirmation mechanism

Message confirmation means that after the producer delivers the message, if the Broker (message entity) receives the message, it will give us a reply. The producer receives the response to determine whether the message is normally sent to the Broker. This method is also the core guarantee for the reliable delivery of the message!

Single confirmation

This is a simple confirmation method. It is a synchronous confirmation publishing method, that is, after publishing a message, only it
After the message is confirmed to be published, subsequent messages can continue to be published. The waitForConfirms() method only after the message is confirmed
If the message is not confirmed within the specified time range, it will throw an exception.
The biggest disadvantage of this confirmation method is that the publishing speed is particularly slow, because if there is no confirmation, the published message will be lost
Blocking the publication of all subsequent messages, which provides a throughput of no more than hundreds of published messages per second. Of course, for someone
This may be enough for some applications.

Batch confirmation

The method of single confirmation is very slow. Compared with a single message waiting for confirmation, publishing a batch of messages first and then confirming together can greatly improve the throughput. Of course, the disadvantage of this method is that when a failure causes a problem in publishing, we don't know which message has a problem. We must save the whole batch in memory, To record important information and then republish the message. Of course, this scheme is still synchronous and will block the release of messages.

Asynchronous acknowledgement

The ConfirmListener() callback method provided by the Channel object only contains delivertag (the message sequence number sent by the current Channel). You need to maintain a cunconfirm message sequence number collection for each Channel, each publish data, element + 1 in the collection, callback the handleAck method once, and delete one (multiple=false) or more (multiple=true) in the unconfirm collection record. From the perspective of program efficiency, this unconfirm set is better to adopt the ordered set SortedSet storage structure

public class Test {

    private static final long MESSAGE_COUNT=1000;
    public static void main(String[] args) throws Exception{
        //Single confirmation
//        Test.danGeQueRen(); // Release 1000 individual confirmation messages, taking 991ms
        //Batch confirmation
        Test.piLiangQueRen(); //It takes 139ms to publish 1000 batch confirmation messages
        //Asynchronous acknowledgement
//        Test.yiBuQueRen(); // Publish 1000 asynchronous confirmation messages, taking 56ms

    }

//    Single confirmation
   static void danGeQueRen() throws Exception {
        Channel channel = Rabbitmqutil.getChannel();
        //The declaration of the queue uses uuid to generate random queue names
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //Open release confirmation
        channel.confirmSelect();
        //start time
        long begin = System.currentTimeMillis();
        //Batch message sending
        for (int i = 1; i < MESSAGE_COUNT ; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
            //Single release confirmation
            boolean flag = channel.waitForConfirms();
            if(flag){
                System.out.println("Message sent successfully");
            }
        }
        //End time
       long end = System.currentTimeMillis();
       System.out.println("release"+MESSAGE_COUNT+"Separate confirmation messages,time consuming"+(end-begin)+"ms");
    }

    //Batch confirmation
    static void piLiangQueRen() throws Exception{
        Channel channel = Rabbitmqutil.getChannel();
        //The declaration of the queue uses uuid to generate random queue names
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //Open release confirmation
        channel.confirmSelect();
        //start time
        long begin = System.currentTimeMillis();
        //Batch message sending
        //Bulk confirmation message size
        int batchSize = 100;

        for (int i = 1; i < MESSAGE_COUNT ; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
            //Batch confirm once when 100 messages are judged

            if(i%batchSize==0){
                //Release confirmation
               channel.waitForConfirms();
            }
        }
        //End time
        long end = System.currentTimeMillis();
        System.out.println("release"+MESSAGE_COUNT+"Batch confirmation messages,time consuming"+(end-begin)+"ms");
    }

    //Asynchronous acknowledgement
    static void yiBuQueRen() throws Exception{
        Channel channel = Rabbitmqutil.getChannel();
        //The declaration of the queue uses uuid to generate random queue names
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,false,false,false,null);
        //Open release confirmation
        channel.confirmSelect();

        /*
        * A thread safe and orderly hash table is suitable for high concurrency
        * 1 Easily associate sequence numbers with messages
        * 2 Easily delete entries in batch, as long as the serial number is given
        * 3 Support high concurrency (multithreading)
        * */
        ConcurrentSkipListMap<Long,String> outstandingConfirms=
                new ConcurrentSkipListMap<>();

        //Message confirmation success callback function
        ConfirmCallback ackCallback = (deliveryTag,multiple)->{
            if(multiple){
                //2 delete the confirmed messages, and the rest are unconfirmed messages
                ConcurrentNavigableMap<Long,String> confirmed=
                        outstandingConfirms.headMap(deliveryTag);
            }else{
                outstandingConfirms.remove(deliveryTag);
            }

            System.out.println("Confirmed message"+deliveryTag);
        };
        /*
         * 1 Tags for messages
         * 2 Batch confirmation
         * */
        //Message confirmation failure callback function
        ConfirmCallback nackCallback = (deliveryTag,multiple)->{
            //3. Print out the unconfirmed messages
            String message = outstandingConfirms.get(deliveryTag);
            System.out.println("The unconfirmed message is"+message+"-->Of unacknowledged messages tag:"+deliveryTag);
        };
        //The message preparation listener listens for which messages succeed and which messages fail
        /*
        * 1 Listen for successful messages
        * 2 Listen for failed messages
        * */
        channel.addConfirmListener(ackCallback,nackCallback);

        //start time
        long begin = System.currentTimeMillis();
        for (int i = 1; i < MESSAGE_COUNT ; i++) {
            String message = i+"";
            channel.basicPublish("",queueName,null,message.getBytes());
            // 1 record the sum of all messages to be sent
            outstandingConfirms.put(channel.getNextPublishSeqNo(), message);
        }
        //End time
        long end = System.currentTimeMillis();
        System.out.println("release"+MESSAGE_COUNT+"Asynchronous acknowledgement message,time consuming"+(end-begin)+"ms");
    }

Execute a single confirmation method in the main function

Perform batch confirmation

Perform asynchronous acknowledgement

Tags: Java RabbitMQ

Posted on Tue, 23 Nov 2021 09:41:46 -0500 by DF7