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"); } }
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