Hello everyone, I’m Xiao CAI. A man who wants to be a man who talks architecture! If you also want to be the person I want to be, or point a concern to do a companion, let small dishes no longer lonely!

This article focuses on message loss for RabbitMQ

Refer to it if necessary

If it is helpful, do not forget the Sunday

Wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!

Yes, finally RabbitMQ!

RabbitMQ interview questions include:

  • Message reliability Problem: How do I ensure that sent messages are consumed at least once?
  • Delayed message problem: How to implement delayed message delivery?
  • High availability issues: How do YOU avoid unavailability issues caused by a single point of MQ failure?
  • Message accumulation problem: How to solve the problem of millions of messages piled up and unable to timely consume?

RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ: RabbitMQ

1. Message reliability

The problem of message reliability might be understood as how to prevent message loss? So why do messages get lost? Let’s take a look at the whole process of message delivery:

From the figure, we can analyze the possible message loss in three stages:

  • Publisher sends messages to the Exchange

  • Exchange is distributed to the queue

  • Queue posts to the customer

Now that we know which phases can cause data loss, we can prevent it from happening at the source.

Engineering structure

The engineering structure is very simple, it is a simple Spring Boot project, there are two modules of consumer and producer

1. The producer send is lost

A Publisher confirm mechanism is provided in RabbitMQ to avoid loss of messages sent to MQ. After the message is sent to MQ, an acknowledgement result is returned to the producer indicating whether the message was successfully acknowledged. There are two requests for this validation result:

  • publisher-confirm

This type is sender confirmation, and there are two cases

  1. Message successfully posted to the switchack
  2. Message not delivered to switch. Returnednack
  • publisher-return

This type is sender’s receipt, and there are two cases

  1. Message is posted to the switch and successfully distributed to the queueack
  2. Message delivered to the switch, but not successfully distributed to the queue, returnsnack

Note: When the acknowledgement mechanism sends messages, you need to set a globally unique ID for each message to distinguish different messages and avoid ACK conflicts

Let’s use code to illustrate how this works

1)The configuration file

Let’s first look at the producer configuration file

The RabbitMQ connection information is not much to explain, let’s take a look at some of the more unfamiliar configurations

  • publisher-confirm-type

Enable send confirmation. Two types are supported

  1. Simple: Waits for the confirm result until time out
  2. Correlated: asynchronous callbacks defined as ConfirmCallback, which MQ calls back when returning results
  • publisher-returns

Turn on public-return, again based on the CallBack mechanism, but defining the ReturnCallback

  • template.mandatory

Defines the policy for routing failures.

  • True: Call ReturnCallback
  • False: Discards the message
2)Define the callback event

Only one ReturnCallback can be configured per RabbitTemplate

3)Send a message

Before executing the send code, we ensure that we have created (a direct-exchange switch, a direct-queue, and a bound key of direct)

Under normal circumstances, our execution code must have been sent successfully, and you can see the green output from the console

And we also received the message successfully in the message queue:

We can change the name of the switch. If the switch cannot be found when sending a message, the switch will return nACK, and we can check whether the switch can enter our code:

The code execution is green, but the message fails to be sent because rabbitMQ cannot find the correct switch, as shown below:

Publish -> queue publish -> queue publish -> queue publish -> queue publish -> queue publish -> queue We can change the route key to make the switch route out of the corresponding queue

The rabbitMQ console can see that the message was successfully delivered to the switch when the switch failed to route to the corresponding queue

Here, we use two kinds of simple error simulation, so that the program can smoothly enter our predefined callback, if the situation of sending failure, we can customize the message retransmission mechanism in the failed callback, to avoid the problem of message loss to the maximum extent

4) summary

We can avoid message loss on the producer -> exchange -> queue link by using publish-confirm and publish-return error trapping mechanisms

  • publisher-confirm
    1. The message was successfully sent to Exchange, returning an ACK
    2. The message failed to be sent to Exchange, returning nACK
    3. If an exception occurs during message sending and no reply receipt is received, failureCallback is performed
  • publisher-return
    1. The message was successfully sent to the Exchange but not routed to the Queue, calling the custom callback function returnCallback

2. The message store is lost

What do I mean by message store missing? The concept of persistence is that when a message has been successfully sent to the queue, it will be lost if the consumer does not consume it and rabbitMQ goes down and restarts.

This is because MQ stores messages in memory by default, and we can ensure that messages are not lost in MQ by enabling persistence

This option can be found when creating a switch or queue using the GUI provided by RabbitMQ

If they are set to durable, we can see that switches and queues still exist no matter how MQ restarts.

But many times our switches and queues are created not on the GUI, but through application code

  • Switch persistence

  • Queue persistence

  • Message persistence

By default, messages sent by AMQP are persistent and do not need to be specified

3, consumer consumption loss

RabbitMQ uses a mechanism that deletes confirmation messages as soon as they are consumed by consumers

So how do you confirm that the message has been consumed by the consumer? This will depend on the receipt for confirmation, and the consumer will need to send an ACK receipt to RabbitMQ to indicate that the message has been processed. Ack has three confirmation modes in AMQP:

  • “Manual” : indicates a manual ACK. You need to invoke the API to send the ACK after the service code is complete
  • Auto: Automatic ACK. Spring monitors whether the listener code is abnormal. If no exception occurs, an ACK is returned
  • None: Turns ack off and MQ deletes the message immediately after delivery

All three methods are done by modifying the configuration file:

1) manual

This method requires the user to confirm manually and has good flexibility

If the execution logic is correct, RabbitMQ will remove the message, but if the execution logic throws an exception and does not enter manual confirmation, RabbitMQ will retain the message:

2) auto

This mode automatically confirms the message when no exception occurs

We changed the validation mode to Auto in the configuration file to test:

There is no problem with receiving messages normally, so let’s also make some exceptions:

We manually created an exception and found that while the message was not deleted by RabbitMQ, the console kept reporting errors and constantly trying to re-consume, which would have been a bit of a crash in an online environment.

When a consumer fails, messages are requeue (re-enqueued) to the queue, re-sent to the consumer, then again exception, requeue again, in an infinite loop, causing MQ’s message processing to spike

The reason for this is because of RabbitMQ’s retry failure mechanism, but many times we may not want to retry all the time, just a few attempts and then give up if it fails. In this case we need to configure retry failure in the configuration file:

After enabling this configuration, we restart the project to observe

Through the console can be seen in the retry after 3 times, SpringAMQP throws an exception AmqpRejectAndDontRequeueException, local retry mechanism effect. And when we return to the RabbitMQ console, we can see that the corresponding message has been deleted, indicating that SpringAMQP returns an ACK, causing the message to be deleted by MQ

But this is not elegant and deleting the message after retry is too violent. Is there a better way to do this? The answer is yes!

This can be done using the MessageRecovery interface provided by AMQP, which is implemented in three different ways:

  • RejectAndDontRequeueRecoverer: retry after running out, reject directly, lost the message. The default mode is adopted above
  • ImmediateRequeueMessageRecoverer: retry after running out, return nack, message to team
  • RepublishMessageRecoverer: retry after running out, the failure message delivered to the designated switch

Three ways can be adopted, according to the different scenarios analysis, it is not difficult to find a third RepublishMessageRecoverer is more elegant ~ when will try again after a failed message delivered to a designated special deposit exception message queue, the follow-up by artificial centralized processing! The specific usage is as follows:

After custom exception handling, we restart the project to view the console:

You can see that after three retries, our exception message enters our custom exception queue

3) none

There is nothing to be said for this method ~ MQ will delete the message whether it is abnormal or not!

4, summarize

If you are asked at this point, how do you ensure the reliability of RabbitMQ messages? Well, you’re gonna have to chew the fat

How do I ensure that messages are not lost?

1) What are the missing scenes first?

Message loss can occur when the message is lost on delivery (not delivered to exchange/not routed to queue), when the message is not persisted and MQ goes down, or when the consumer receives the message and fails to consume it correctly

2) And how to prevent it
  • Enable the producer confirmation mechanism to ensure that messages from producers can reach queues

Confirmation mechanisms include publisher-confirm and publisher-return

When the delivery fails to reach the switch, we can confirm the ack and NACK returned by publisher-confirm

If the switch fails to route to the queue, this can be confirmed by the publisher-return custom callback function. Only one ReturnCallback can be configured per RabbitTemplate

  • Enable persistence to ensure that messages are not lost in the queue before being consumed

Persistence is classified into switch persistence, queue persistence, and message persistence. Durable is required to be set to true

  • When the consumer confirmation mechanism is enabled, the minimum isautolevel

There are three types of consumer confirmation mechanisms: manual, Auto, and None

  • Failure retry mechanism

We manually MessageResoverer RepublishMessageRecoverer way, abnormal transfer delivery failed messages to the queue, to the artificial processing


After this one-two punch, the interviewer has to silently admit that you have something?

Of course, this is just one of RabbitMQ’s problems, and we’ll continue with the other fixes next

Don’t talk, don’t be lazy, and xiao CAI do a blowing bull X do architecture of the program ape ~ point a concern to do a companion, let xiao CAI no longer lonely. See you later!

Today you work harder, tomorrow you will be able to say less words! I am xiao CAI, a man who grows stronger with you. 💋 wechat public number has been opened, xiao CAI Liang, did not pay attention to the students remember to pay attention to oh!