Please do not create a connection/channel every time you send a message
Creating a connection in RabbitMQ is a time-consuming/resource-consuming operation. Each connection uses at least 100KB of memory, and too many connections will increase the memory pressure on the Broker. It is recommended to create a connection when the program starts and reuse this long connection every time a message is sent to improve sending performance and reduce server memory usage.
Channels are a lighter form of communication and it is recommended to use as many channels as possible to reuse connections. However, it is best not to use the same channel across threads concurrently, as many RabbitMQ client implementations are not thread-safe.
Set a reasonable send timeout time for producers
RabbitMQ clients of different languages and versions have set different default send times, with some clients having an excessively long default timeout, such as 580 seconds or 900 seconds. In the event of a network anomaly, an excessively long send timeout can block the sending thread and even cause an avalanche effect. It is recommended to set a reasonable timeout time according to the business scenario, with 3 seconds being a recommended value.
Producers and consumers use separate connections
Due to RabbitMQ's unique flow control mechanism, if producers and consumers reuse the same physical connection, and the consumer traffic triggers flow control, it may cause the producer to be flow-controlled, leading to slow sending or timeouts. Therefore, it is recommended that producers and consumers use different physical connections during initialization to avoid mutual interference.
It is not recommended for consumers to enable automatic message acknowledgment
RabbitMQ server provides at least once delivery semantics to ensure that messages are correctly delivered to downstream business systems. Once the consumer enables automatic message acknowledgment, the server will automatically confirm and delete the message after pushing it to the consumer side, even if there is an exception during message processing, which may lead to missed message processing in the business.
Consumer idempotent processing of messages
RabbitMQ server provides at least once delivery semantics, and in extreme cases, messages may be delivered repeatedly. Therefore, it is recommended that key business processes must perform idempotent processing when handling messages, so that even if duplicate messages are received, there will be no negative business impact.
Business idempotent processing can be achieved by adding a unique business identifier to the message, and the consumer checks such identifiers and message status during consumption, processing duplicate messages according to business needs, ensuring that even if duplicate messages are received, there will be no negative business impact.
Limit queue length to avoid a large accumulation of messages
An excessively long queue (a large accumulation of messages) will occupy a lot of memory and consume more server system resources. Not only does it take longer to perform state synchronization during operation, but it also leads to a significant increase in the startup recovery time of the server Broker.
A shorter queue will provide faster processing speed and system performance.
Therefore, it is necessary for the client to improve the consumption capacity as much as possible, and use queue dimension limitations such as max-length to ensure that the queue is as short as possible.
Use Consume or Get to consume messages?
Get is a polling-based pull consumption mode where each message consumed requires a request to be sent to the Broker. If there are no messages in the queue, it might result in a large number of ineffective empty pulls leading to resource occupation. On the other hand, Consume can receive a batch of messages at once, with the server pushing messages based on actual conditions. In most cases, Consume should be used instead of Get for message consumption.
If the business process must use Get to consume messages, attention should be paid to the Get mechanism at the business level to avoid continuous Get Empty pulls (when the queue has no messages pending consumption, but the consumer continuously performs Get), causing high server CPU load.
Set a reasonable Prefetch Count for consumers
Prefetch setting is a mechanism where the consumer side, in order to improve consumption throughput, pushes messages to the consumer’s cache in advance, reducing consumption waiting time and latency. However, if the Prefetch Count is too high or unlimited, it can lead to a large number of messages being cached on the consumer side, and the server Broker also maintaining the state of unacknowledged messages in memory, occupying a lot of resources; if messages remain in unacknowledged state, these messages cannot be consumed by other idle consumers, manifesting as increased consumption delay or unbalanced consumer load.
It is recommended to set the Prefetch Count within a reasonable range according to the business consumption rate.
Set a reasonable exception handling strategy for consumers
When consuming messages, encountering unprocessable exceptions, messages not set for automatic acknowledgment will trigger message retries. If the exception continues without a normal exit, it will trigger infinite retries of the message, not only causing a high load on the Broker side but also preventing subsequent messages from being reasonably consumed.
Ensure client reconnection mechanism
In extreme scenarios such as OOM, host machine failure, etc., the server Broker may self-heal and restart. Everyday business operations such as cluster upgrade can also trigger Broker restart. To avoid continuous connection exceptions during the Broker's restart period, please ensure that the client has implemented an automatic reconnection mechanism.
Do not disable the heartbeat setting in the client SDK
heartbeat has a configuration value on both the server and client side (60 seconds for the server), the effective heartbeat is determined through negotiation between the server and client, and different languages/versions of clients have different negotiation mechanisms. Setting heartbeat=0 on the client side, which turns off heartbeat detection, will prevent the server from automatically removing long-term idle connections, potentially leading to unexpected connection leaks.