We know that RocketMQ is a high performance, high reliability distributed messaging middleware, and high performance and high reliability are difficult to achieve together. Because to ensure high reliability, data must be persisted to disk, which may not guarantee high performance.

RocketMQ does a good job of accommodating both, starting with disks. Modern disks are high-performance, and write speeds are not necessarily slower than data transfer over a network. For example, the sequential write speed of an SSD using the m. 2 NVMe protocol can reach 1500 MB/s, and that of a common disk with high performance can reach 450MB/s to 600MB/s.

In the case of sequential write speed, but without manual control, the disk uses random write. In the case of random write speed, the disk write speed decreases rapidly. The random write speed of the disk may only be a few hundred KB/s, which is far slower than the network transmission speed, so it cannot meet the requirements of high performance.

In the design of Persistence, RocketMQ adopts a sequential write and random read strategy to take advantage of sequential disk write speed so that disk write speed does not become a bottleneck of the system. And use MMPP this “zero copy” technology, improve the speed of message storage and network transmission. To meet RocketMQ’s high performance, high reliability requirements.

The RocketMQ persistence mechanism is designed to ensure high performance.

In the RocketMQ persistence mechanism, three roles are involved:

  • CommitLog: The real storage file for messages. All messages are stored in the CommitLog file.
  • ConsumeQueue: a logical queue for message consumption, similar to an index file in a database.
  • IndexFile: message IndexFile, which stores the mapping between message keys and offsets to improve message retrieval speed.

CommitLog files are places where message data is stored. All messages are stored in CommitLog files. After a producer sends a message to a RocketMQ Broker, the Broker server writes the message sequentially to a CommitLog file. This is why RocketMQ performs well, because we know that disk sequentially writes are extremely fast. RocketMQ takes advantage of this. Greatly improves message writing efficiency.

Each consumer can only subscribe to one topic. Consumers care about all messages on a subscribed topic, but messages on the same topic may not be consecutive in the CommitLog file. Therefore, when consumers consume messages, You need to load CommitLog files into memory to traverse for messages on subscribed topics, and performance deteriorates rapidly with frequent I/O operations.

To solve this problem, RocketMQ introduces the Consumequeue file. The Consumequeue file can be considered an index file, similar to a secondary index in MySQL. When all messages under the same topic are stored, consumers only need to fetch messages from the corresponding Consumequeue group. The Consumequeue file does not store the full information of the message. If you are familiar with MySQL indexes, you should understand this. The specific fields stored here are highlighted in the figure above. There are two benefits to doing this:

  • Since the Consumequeue file is small, you can ensure that all Consumequeue files are read into the memory as much as possible to improve consumption efficiency.
  • The Consumequeue file is also persistent, so not storing the full information saves disk space.

IndexFile is an IndexFile built by RocketMQ for message subscriptions to speed up the retrieval of messages by topic and message queue, which I won’t go into detail.

So much for the RocketMQ persistence mechanism, let’s talk about flushing message data.

Because of the existence of the operating system PAGECACHE, PAGECACHE is OS on the file cache, used to speed up the file read and write, so are generally written to PAGECACHE first, and then persistent to disk. This is true of other components we are familiar with, MySQL, Redis, etc. RocketMQ is no exception.

RocketMQ provides synchronous and asynchronous flushes. You can set the flushDiskType parameter (SYNC_FLUSH and ASYNC_FLUSH) in the Broker configuration.

Asynchronous flush mode (default) : When a message is written to the PAGECACHE in the memory, the client immediately sends a message indicating that the write operation is successful. When the number of messages in the PAGECACHE reaches a certain level, a write operation is triggered to write the messages in the PAGECACHE to the disk. This mode has large throughput and high performance, but data in PAGECACHE may be lost and data security cannot be guaranteed.

Synchronous flush mode: After the message is written to the PAGECACHE of the memory, the flush thread is notified to flush the disk immediately and waits for the flush completion. After the flush completion, the waiting thread wakes up and returns to the status that the message is written successfully. This method can ensure absolute data security, but the throughput is not large.

That’s it for RocketMQ persistence. Thank you for reading this article and I hope you found it helpful. If there is a harvest, you can also help recommend it to other small partners, so that more people benefit, thank you very much.

Welcome to pay attention to the public number [Internet crew head brother]. There are workplace insights, Java technology, although not high – profile, but easy to understand. Today’s best is tomorrow’s minimum requirements, I wish you and I progress together.