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