The most complete RabbitMQ introductory tutorial in history takes you in-depth study from scratch - release confirmation

Posted by ViN86 on Wed, 05 Jan 2022 23:52:06 +0100

RabbitMQ (VII) - release confirmation

Release confirmation principle

The producer sets the channel to confirm mode. Once the channel enters the confirm mode, all messages published on the channel will be assigned a unique ID (starting from 1). Once the message is delivered to all matching queues, the broker will send a confirmation to the producer (including the unique ID of the message), This enables the producer to know that the message has correctly arrived at the destination queue. If the message and queue are persistent, the confirmation message will be sent after writing the message to the disk. The delivery tag field of the confirmation message returned by the broker to the producer contains the sequence number of the confirmation message. In addition, the broker can also set basic The multiple field of ACK indicates that all messages before this serial number have been processed.

The biggest advantage of confirm mode is that it is asynchronous. Once a message is published, the producer application can continue to send the next message while waiting for the channel to return the confirmation. After the message is finally confirmed, the producer application can process the confirmation message through the callback method. If RabbitMQ loses the message due to its own internal error, A nack message is sent, and the producer application can also process the nack message in the callback method.

Method for opening release confirmation

Get information
Publishing confirmation is not enabled by default. If you want to enable it in the publisher, you need to call the method confirmSelect. Whenever you want to use publishing confirmation, you need to call this method in channel

Single confirmation release

This is a simple confirmation method. It is a synchronous confirmation publishing method, that is, after publishing a message, only it is confirmed to be published, and subsequent messages can continue to be published. waitForConfirmsOrDie(long) returns only when 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 the published messages are not confirmed, the publishing of all subsequent messages will be blocked. This method provides a throughput of no more than hundreds of published messages per second. Of course, this may be sufficient for some applications.

code implementation

package com.study.rabbitmq.four;

import com.rabbitmq.client.Channel;
import com.study.rabbitmq.utils.RabbitMQUtils;

import java.util.UUID;

//Validation release confirmation mode, single confirmation
public class Individually {
    //Batch send 1000 messages
    public static int MESSAGE_COUNT = 1000;
    public static void main(String[] args) throws Exception {
        //1. Single confirmation
        Channel channel = RabbitMQUtils.getChannel();
        //Queue declaration
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //Open release confirmation
        // Add group 1025684353 to blow water and chat -- >
        channel.confirmSelect();
        //start time
        long begin = System.currentTimeMillis();
        //Batch message sending
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "";
            channel.basicPublish("",queueName,null,message.getBytes());
            //Release confirmation of a single message immediately
            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 release

Get information
The above method 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 blocks the release of messages.

code implementation

package com.study.rabbitmq.four;

import com.rabbitmq.client.Channel;
import com.study.rabbitmq.utils.RabbitMQUtils;

import java.util.UUID;

public class Batch {
    //Batch send 1000 messages
    public static int MESSAGE_COUNT = 1000;

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();
        //Queue declaration
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //Open release confirmation
        // Add group 1025684353 to blow water and chat -- >
        channel.confirmSelect();
        //start time
        long begin = System.currentTimeMillis();
        //Size of bulk confirmation message
        int batchSize = 100;

        //Send messages in batch and publish confirmation in batch
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = i + "";
            channel.basicPublish("",queueName,null,message.getBytes());
            //When 100 messages are judged, batch confirmation is performed once
            if (i%batchSize == 0){
                //Release confirmation
                channel.waitForConfirms(batchSize);
            }
        }

        //End time
        long end = System.currentTimeMillis();
        System.out.println("release"+MESSAGE_COUNT+"Batch confirmation messages, time consuming" + (end - begin) + "ms");
    }
}

Asynchronous confirmation release (key)

Although the programming logic of asynchronous confirmation is more complex than the above two, it has the highest cost performance. It can not be said whether it is reliable or efficient. It uses callback function to achieve reliable message delivery. This middleware also ensures whether it is delivered successfully through function callback. Let's explain in detail how asynchronous confirmation is realized.

Processing asynchronous unacknowledged messages

The best solution is to put unconfirmed messages into a memory based queue that can be accessed by the publishing thread. For example, use the ConcurrentLinkedQueue queue to transfer messages between confirm callbacks and the publishing thread.
Get information

code implementation

package com.study.rabbitmq.four;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmCallback;
import com.study.rabbitmq.utils.RabbitMQUtils;

import java.util.UUID;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

public class messageAsync {
    //Batch send 1000 messages
    public static int MESSAGE_COUNT = 1000;
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtils.getChannel();
        //Queue declaration
        String queueName = UUID.randomUUID().toString();
        channel.queueDeclare(queueName,true,false,false,null);
        //Open release confirmation
        channel.confirmSelect();
        // Add group 1025684353 to blow water and chat -- >

        /*
        * Thread safe and orderly hash table, suitable for high concurrency
        * Function:
        * 1.Associate the sequence number with the message key:value
        * 2.As long as the serial number is given, the entries can be deleted in batch
        * 3.Support high concurrency (multithreading)
        * */
        ConcurrentSkipListMap<Long,String> outstandingConfirms = new ConcurrentSkipListMap<>();

        /*
         * Message confirmation succeeded
         * 1.Tags for messages
         * 2.Batch confirmation
         * */
        ConfirmCallback confirmCallback = (deliveryTag, multiple) -> {
            //2, Delete confirmed messages in batch, and the rest are unconfirmed messages
            if (multiple){
                ConcurrentNavigableMap<Long, String> confirmed = outstandingConfirms.headMap(deliveryTag);
                confirmed.clear();//Clean up confirmed messages
            }else {
                //Single delete confirmed message
                outstandingConfirms.remove(deliveryTag);
            }
            System.out.println("Confirmed message:"+deliveryTag);
        };
        /*
        * Message confirmation failed
        * 1.Tags for messages
        * 2.Batch confirmation
        * */
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            //3, Processing unconfirmed message printing
            String message = outstandingConfirms.get(deliveryTag);
            System.out.println("Unacknowledged messages are:"+message+"---------Unacknowledged message flags:"+deliveryTag);
        };

        //The message listener monitors which messages are sent successfully and which messages are sent failed
        /*
        * 1.Listen for which messages are sent successfully
        * 2.Listening for which messages failed to send
        * */
        channel.addConfirmListener(confirmCallback,nackCallback);//Asynchronous notification

        //start time
        long begin = System.currentTimeMillis();
        //Batch send messages
        for (int i = 0; i < MESSAGE_COUNT; i++) {
            String message = "news" + i;
            channel.basicPublish("",queueName,null,message.getBytes());
            //Processing asynchronous unacknowledged messages
            // 1, Record the sum of all messages to be sent
            //channel.getNextPublishSeqNo(): message sequence number
            outstandingConfirms.put(channel.getNextPublishSeqNo(),message);
        }

        //End time
        long end = System.currentTimeMillis();
        System.out.println("release"+MESSAGE_COUNT+"Asynchronous acknowledgement messages, time consuming" + (end - begin) + "ms");

    }
}

Get information

Comparison of the above three release confirmation speeds

Publish message separately

  • Synchronization waiting for confirmation is simple, but the throughput is very limited.

Batch publish message

  • Batch synchronization waits for confirmation. It is simple and reasonable throughput. Once there is a problem, it is difficult to infer that the message has a problem.

Asynchronous processing:

  • Optimal performance and resource usage can be well controlled in case of errors, but it is slightly difficult to implement

Finally, I wish you success in your studies as soon as possible, get a satisfactory offer, get a quick promotion and raise, and reach the peak of your life. If you can, please give me a third company to support me. I'll see you next time

Get information

Topics: Java RabbitMQ queue message queue