Message Sending Process in RocketMQ
In the high-performance message queue system of RocketMQ, the process of sending messages is a critical link that ensures system reliability and real-time performance. A complete sending process is not simply "writing to disk"; it involves complex interactions among producers, Broker clusters, and underlying storage components. This article will deeply analyze the entire process from invoking the send interface to the final persistence of messages on disk, helping developers understand how data flows in distributed systems.
Connection Establishment Between Producer and Broker
The first step in message sending is establishing a connection between the producer (Producer) and the Broker cluster. When initializing in code, the producer configures NameServer addresses to discover available Broker nodes. Once it obtains the IP address and port of the target Broker, the producer initiates a handshake request via TCP protocol. After completing the three-way handshake, a long-lived connection is established.
During this phase, metadata exchange also occurs between both parties. The Broker returns configuration parameters such as master-slave topology information for its cluster, current load status, and supported compression algorithms to the producer. Based on this information, the producer adjusts its own sending strategy—for example, selecting specific Broker nodes for communication or negotiating more efficient transmission protocols (such as TCP NIO). This connection establishment process not only ensures network channel stability but also lays the foundation for subsequent concurrent transmission of batch messages.
Message Serialization and Routing Decision
When the send method is invoked, the producer first performs serialization operations on application-layer business objects. RocketMQ supports multiple serialization protocols, including Java's native Serializable, Protobuf, JSON, etc. The serialized byte stream is encapsulated in a Message object and appended with necessary message header information (Header), such as transaction status, priority, delay level, etc.
Immediately following this is the routing decision phase. This represents the core logic for load balancing implemented by RocketMQ. Producers do not blindly send messages to any Broker; instead, they calculate routes based on configured sending strategies:
- Random Sending: Sends a message to an arbitrarily available Broker within the cluster.
- Round-Robin Sending: Sequentially accesses different Brokers according to a preset order, preventing excessive pressure on hot nodes.
- Specific Sending: Directs messages to specific Broker addresses pre-configured by the user.
The system dynamically adjusts routing strategies based on the current health status of the cluster. If a Broker node is in a failed or overloaded state, the producer automatically excludes that node, ensuring messages are delivered to healthy nodes and thereby improving overall system availability.
Synchronous and Asymmetric Sending Mechanisms
RocketMQ provides flexible sending modes, primarily manifested as synchronous and asynchronous forms, which differ significantly in performance characteristics and resource consumption.
Synchronous sending is blocking. After the caller initiates a request, it must wait until the message successfully writes to disk (or reaches the preset persistence threshold) before returning results. While this method guarantees strong data consistency, it consumes significant thread resources under high concurrency scenarios and may lead to reduced application throughput due to network latency or slow Broker responses.
Asynchronous sending, conversely, is non-blocking. After the producer sends a message to the Broker, it immediately returns control flow back to the caller without waiting for write completion. Upon receiving messages, the Broker places them into local queues for buffering and processing. This approach significantly boosts system throughput but sacrifices some real-time performance, as callers cannot perceive whether messages have truly persisted at the code level. In practical engineering scenarios, asynchronous sending is typically recommended in combination with retry mechanisms to balance performance and reliability.
Message Persistence Strategy
After receiving a message from the Broker, it undergoes three stages: memory buffering, disk persistence (writing), and flushing. This process directly determines RocketMQ's data reliability.
Firstly, the Broker places newly received messages into local memory queues (Queue). To cope with sudden traffic spikes, these memory queues usually have capacity limits; when a queue is full, the system adopts strategies such as "reject," "discard," or "expand" based on configuration.
Subsequently, messages are asynchronously flushed to disk. RocketMQ employs an efficient log storage structure (LogStore), recording messages in files via append-write operations. This design avoids random read/write impacts on disks and significantly improves write performance. Under default configurations, the Broker periodically executes flush operations to synchronize data from memory onto SSDs or HDDs.
For critical business scenarios, a "sync-flush" mode can also be enabled. In this mode, messages are only returned to the producer after confirmation that they have been successfully written to disk and flushed. Although this further reduces the risk of data loss, it significantly increases latency; therefore, its use should be exercised with caution in high-throughput scenarios where low-latency requirements are not stringent.
Exception Handling and Retry Mechanisms
In actual operation, network jitter or transient Broker failures are inevitable. RocketMQ includes comprehensive exception handling and retry mechanisms to address these situations.
If a SendException occurs during the sending process, the producer decides whether to resend based on configured sendTimeout and retryTimes parameters. For asynchronous sending modes, if messages timeout in memory processing without persisting, the Broker triggers automatic retry logic; for synchronous sending, if exceptions occur at the network layer or application layer, callers can catch these exceptions and manually initiate retry requests.
Furthermore, RocketMQ supports special exception handling strategies under various network models such as "half-duplex" and "full-duplex." By reasonably configuring retry intervals, maximum retry counts, and filtering rules for dead-letter queues (DLQ), one can effectively prevent message accumulation and system avalanches caused by infinite loop retries.
In summary, RocketMQ's message sending process is a comprehensive engineering project integrating connection management, routing optimization, serialization conversion, persistent storage, and fault tolerance mechanisms. Understanding this flow helps developers make more reasonable architectural decisions when designing highly available distributed systems, ensuring accurate delivery and efficient data flow of messages in complex network environments.