RabbitMQ consumer ack mechanism

Keywords: Java RabbitMQ

ACK mechanism

What is a message acknowledgement ACK

If an exception occurs when the consumer's server processes a message during message processing, the message being processed may not complete message consumption and data will be lost. To ensure that data is not lost, RabbitMQ supports message determination - ACK.

Message confirmation mechanism of ACK

The ACK mechanism is that after the consumer receives a message from RabbitMQ and processes it, it feeds back to RabbitMQ, and RabbitMQ deletes the message from the queue after receiving the feedback.
If a consumer has network instability and server exceptions when processing a message, there will be no ACK feedback. RabbitMQ will think that the message is not consumed normally and will put the message back into the queue.
In the case of a cluster, RabbitMQ will immediately push this message to other online consumers. This mechanism ensures that no messages and tasks are lost when the consumer server fails.
Messages will never be deleted from RabbitMQ. Messages will not be deleted from RabbitMQ server data until consumers correctly send ACK feedback and RabbitMQ confirms receipt.

Development considerations of ACK mechanism

If you forget ACK, the consequences are serious. When the Consumer exits, the Message will always be redistributed. Then RabbitMQ will occupy more and more content. Because RabbitMQ runs for a long time, this "memory leak" is fatal.

Code demonstration

spring:
  #rabbit configuration information
  rabbitmq:
    #Publisher confirmation
    publisher-confirms: true
    #The startup message fails and returns. This interface triggers a callback when the switch route cannot reach the queue
    publisher-returns: true
    template:
      #Enable mandatory information; Default false
      mandatory: true
    listener:
      simple:
        #Set the consumer to manually ack none auto auto confirm manual manual confirm
        acknowledge-mode: manual
        #Automatically start container on startup
        auto-startup: true
        #Specify how many messages a request can process. If there are transactions, the number must be greater than or equal to the number of transactions
        prefetch: 10
        #Decide whether the rejected message will rejoin the team; The default is true (related to the parameter acknowledge mode) 
        default-requeue-rejected: false
        retry:
          #Is listening retry available
          enabled: true

For consumer consumption messages, manually throw run-time exceptions after the printout, and observe the phenomenon.

/**
 * @author KimWu
 * @Description : 
 */
@Slf4j
@Component
@RabbitListener(
        //Bind queue
        bindings = @QueueBinding(
                //The name of the queue needs to be specified
                value = @Queue(
                        //Configure queue name
                        value = "${rabbitmq.tenant.menu.name}",
                        //Is it a temporary queue that can be deleted -- > message persistence
                        autoDelete = "false"
                ),
                //Configuration switch
                exchange = @Exchange(
                        //Specify switch name
                        value = "${rabbitmq.tenant.menu.exchange}",
                        //Specify the specific exchanger type, which is specified by the constant class
                        type = ExchangeTypes.DIRECT
                ),
                //Routing key
                key = "${rabbitmq.tenant.menu.routingkey}"
        )
)
public class TenantMenuListen {

    @Resource
    private AuthSysMenuService authSysMenuService;


    /**
     * The method of receiving messages adopts the message queue listening mechanism
     */
    @RabbitHandler
    @GlobalTransactional(rollbackFor = Exception.class)
    public void pay(String msg, Message message, Channel channel) throws Exception {
        /**
         * At present, this method mainly synchronizes the menu
         */
        try {
 			if(1 = 1){
 				throw new RuntimeException();
 			}
            //Consumer manual ack mechanism
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Observe the phenomenon as follows:

In the RabbitMQ browser interface, you can see the message confirmation mechanism that a message has not been ACK. This message is locked unacknowledged, so it has been reporting errors on the console.


The console effect is as follows * *. The message has been sent all the time because the consumer has not returned ACK confirmation. RabbitMQ thinks that the message has not been consumed normally. It will put the message in the queue again for you to consume again, but it still does not return ACK confirmation, forming an endless loop**

How to solve the problem? If an exception occurs in the program when the message is sent, the consequences are very serious, which will lead to memory leakage, so you can use the ack confirmation mechanism of RabbitMQ. Enable retry, and then the number of retries. The default is 3. This is set to 5 times.

spring:
  #rabbit configuration information
  rabbitmq:
    #Publisher confirmation
    publisher-confirms: true
    #The startup message fails and returns. This interface triggers a callback when the switch route cannot reach the queue
    publisher-returns: true
    template:
      #Enable mandatory information; Default false
      mandatory: true
    listener:
      simple:
        #Set the consumer to manually ack none auto auto confirm manual manual confirm
        acknowledge-mode: manual
        #Automatically start container on startup
        auto-startup: true
        #Specify how many messages a request can process. If there are transactions, the number must be greater than or equal to the number of transactions
        prefetch: 10
        #Decide whether the rejected message will rejoin the team; The default is true (related to the parameter acknowledge mode) 
        default-requeue-rejected: false
        retry:
          #Is listening retry available
          enabled: true
          # retry count
          max-attempts: 5

The effect is as follows:

You can see that the console will not retry after 5 attempts.


It can be seen from the RabbitMQ interface that the initial effect is the same as that above, but after 5 attempts, it becomes 0. RabbitMQ dropped this message.


Summary:
When performing ack, the number of retries must be set, otherwise it is easy to cause memory leakage

Posted by autumn on Wed, 13 Oct 2021 18:04:45 -0700