Note: 1. If you have not worked with RocketMQ before, please read the appendix to understand the overall architecture and terminology of RocketMQ 2. MQServer and Broker in this article represent the same concept

As a key component to realize the scalability and scalability of distributed system, distributed message system needs high throughput and high availability. When it comes to the design of messaging systems, two problems cannot be avoided:

RocketMQ is a high-performance, high-throughput messaging middleware from Alibaba. How does RocketMQ solve these two problems? What are the key features of RocketMQ? How does it work?

Key features and implementation principles

1. Sequential messages

Message ordering refers to the ability to consume a class of messages in the order in which they are sent. For example, an order generates three messages: order creation, order payment, and order completion. When you consume, it makes sense to consume in this order. But at the same time, orders can be consumed in parallel.

If a producer produces two messages, M1 and M2, what can be done to ensure the order of the two messages? Something like this might come to mind:




You might use this method to ensure message order

After M1 is sent to S1, M2 is sent to S2. To ensure that M1 is consumed before M2, it is necessary to notify S2 when M1 arrives at the consumer, and then S2 sends M2 to the consumer.

The problem with this model is that if M1 and M2 are sent separately to two servers, there is no guarantee that M1 will arrive first, and therefore M1 will be consumed first, and the order of messages will need to be maintained in the MQ Server cluster. So how to solve it? A simple way is to send M1 and M2 to the same Server:




Guarantee message order, your improved method

This ensures that M1 arrives at the MQServer before M2 (the client waits for M1 to succeed and then sends M2). According to the principle of first arrived, first consumed, M1 will be consumed before M2, thus guaranteeing the order of messages.

This model, in theory, guarantees the order of messages, but in practice you should encounter the following problems:




Network Latency

As soon as messages are sent from one server to another, there are network latency issues. As shown in the figure above, if it takes longer to send M1 than M2, M2 is consumed first, and the order of the messages is still not guaranteed. Even if M1 and M2 reach the consumer end at the same time, M2 may still be consumed before M1 because the load of consumer end 1 and consumer end 2 is not clear. How to solve this problem? You can send M1 and M2 to the same consumer. After M1 is sent, M2 can be sent only after the consumer responds successfully.

But this raises another question. If consumer 1 does not respond after sending M1, should it continue to send M2 or resend M1? Generally, in order to ensure that the message will be consumed, it will choose to resend M1 to another consumer 2, as shown in the figure below.




Ensure proper posture of message order

In this model, the order of messages is strictly guaranteed. If you are careful, you will still find the problem. There are two situations when consumer 1 does not respond to the Server, one is that M1 does not arrive, and the other is that consumer 1 has responded, but the Server does not receive. In the second case, resending M1 will result in repeated consumption of M1. This is our second problem, message duplication.

Looking back at message ordering, strict sequential messages are easy to understand and easy to handle. A simple and feasible way to implement strict sequential messages is:

Ensure that producer-MQServer-consumer relationships are one-to-one

However, in this design, parallelism becomes a bottleneck in the messaging system (insufficient throughput) and leads to more exception handling. For example, whenever a problem occurs on the consumer side, the entire processing process is blocked and we have to spend more effort to solve the problem of blocking.

But our ultimate goal is high fault tolerance and high throughput for clustering. This seems like an irreconcilable contradiction, so how did Ali solve it?

The easiest way in the world to solve a computer problem: “Just” doesn’t need to solve it! – shen polling

Some problems, seemingly important, can be avoided by design or by breaking them down. It is actually wasteful and inefficient to spend time trying to solve them. From this perspective, we can draw two conclusions about the order of messages:

2. Queue disorder does not mean message disorder

Finally, we look at RocketMQ’s implementation of sending sequential messages from a source code perspective.

Generally, messages are sent by polling all queues (load balancing policy), and sequential messages can be sent to the same queue based on business, such as messages with the same order number. In the following example, messages with the same OrderId are sent to the same queue:

RocketMQ provides two MessageQueueSelector implementations by default: Hash SendResult = producer. Send (MSG, new MessageQueueSelector() { @Override public MessageQueue select(List mqs, Message msg, Object arg) { Integer id = (Integer) arg; int index = id % mqs.size(); return mqs.get(index); } }, orderId);Copy the code

After obtaining the routing information, a queue will be selected according to the algorithm implemented by MessageQueueSelector. The queue obtained by the same OrderId is the same queue.

Private SendResult send() {// Get TopicPublishInfo TopicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); if (topicPublishInfo ! = null && topicPublishInfo.ok()) { MessageQueue mq = null; / / according to our algorithm, select a send queue / / arg here = orderId mq = selector. Select (topicPublishInfo. GetMessageQueueList (), MSG, arg); if (mq ! = null) { return this.sendKernelImpl(msg, mq, communicationMode, sendCallback, timeout); }}}Copy the code
Second, message repetition

In solving the message order problem above, a new problem was introduced, namely message duplication. So how does RocketMQ solve the problem of message duplication? Or “just” does not solve.

The root cause of message duplication is that the network is unreachable. As long as data is exchanged over the network, this problem cannot be avoided. So the solution to this problem is not to solve it, but to bypass it. The question then becomes: what if the consumer receives two identical messages?

2. Ensure that each message has a unique number and ensure that the message processing success and the log of the deduplication table appear at the same time

The first rule is easy to understand. As long as idempotency is maintained, no matter how many duplicate messages are sent, the result will be the same. The second principle is to use a log table to record the ID of a message that has been successfully processed. If the new message ID is already in the log table, the message is not processed.

We can see that the solution to the first clause, which should obviously be implemented on the consumer side, is not part of the messaging system’s intended functionality. Article 2 can be implemented either on the message system or on the business side. The probability of repeated messages is not necessarily high under normal circumstances, and if implemented by a messaging system, it will have an impact on the throughput and high availability of the messaging system, so it is best to let the business side handle the problem itself, which is why RocketMQ does not solve the problem of repeated messages.

RocketMQ does not guarantee message non-duplication, and if your business needs to guarantee strict message non-duplication, you need to do it yourself on the business side.

Transaction messages

RocketMQ supports transactional messages in addition to regular and sequential messages. Let’s start by discussing what transaction messages are and the need to support them. Let’s take a transfer scenario to illustrate the problem: Bob transfers $100 to Smith.

In a standalone environment, the transaction would look something like this:




Schematic diagram of transfer transaction in single machine environment

When users grow to a point where Bob and Smith’s account and balance information are no longer on the same server, the flow looks like this:




Schematic diagram of transfer transaction in cluster environment

At this time, you will find that the same transfer business, in the cluster environment, the time is exponentially increased, which is obviously unacceptable. So how do we get around this problem?

Large transaction = small transaction + asynchronous

Break large transactions into smaller transactions for asynchronous execution. This basically optimizes the execution efficiency of cross-machine transactions to be consistent with that of a single machine. The transfer transaction can be broken down into the following two small transactions:




Small transactions + asynchronous messages

In the figure, the execution of the local transaction (deduction from Bob’s account) and the sending of the asynchronous message should be either successful or failed at the same time. In other words, if the deduction is successful, the sending of the message must be successful. If the deduction fails, the message cannot be sent again. The question is: do we deduct or send the message first?

First let’s take a look, first send a message, the rough schematic diagram is as follows:




Transaction messages: Send messages first

The problem is that if the message is sent successfully but the deduction fails, the consumer will consume the message and add money to the Smith account.

We can’t send the message first, so we can deduct the money first. The schematic diagram is as follows:




Transaction message – Debit first

The problem is similar: if the deduction is successful and the message fails to be sent, Bob is deducted, but no money is added to Smith’s account.

There are many ways to solve this problem, such as putting the message directly into the transaction that Bob deducts, throwing an exception if the message fails, and rolling back the transaction. This approach also conforms to the principle that “just happens” does not need to be solved. RocketMQ supports transactional messages, and let’s take a look at how RocketMQ does this.




The RocketMQ implementation sends transaction messages

RocketMQ phase 1 sends Prepared and gets the address of the message, phase 2 performs local transactions, and Phase 3 accesses the message using the address obtained in phase 1 and changes the state. If you are careful, you may find the problem again. What if the confirmation message fails to be sent? RocketMQ periodically scans the message cluster for transaction messages. When it finds Prepared, it confirms to the sender whether Bob’s money has been reduced or not. If you subtract, do you roll back or continue sending confirmation messages? RocketMQ decides whether to roll back or continue sending confirmation messages based on policies set by the sender. This ensures that message delivery and the local transaction both succeed or fail at the same time.

Let’s take a look at the RocketMQ source code and see if this is how transaction messages are handled. Part of the client sends a transaction message (please see the complete code: rocketmq – under the project example of com. Alibaba. Rocketmq. Example. Transaction. TransactionProducer) :

// As mentioned above, when RocketMQ finds' Prepared 'messages, According to the Listener implementation strategy for determination of transaction TransactionCheckListener TransactionCheckListener = new TransactionCheckListenerImpl (); // Construct the producer of the transaction message TransactionMQProducer Producer = new TransactionMQProducer("groupName"); / / set the transaction decision-making processing class producer. SetTransactionCheckListener (transactionCheckListener); TransactionExecuterImpl tranExecuter = new TransactionExecuterImpl(); TransactionExecuterImpl = new TransactionExecuterImpl(); Producer.start () // create MSG, omit Message MSG = new Message(......) ; / / send a message SendResult SendResult = producer. SendMessageInTransaction (MSG, tranExecuter, null); producer.shutdown();Copy the code

Then look at the source code for the sendMessageInTransaction method, which is divided into three stages: send Prepared, execute the local transaction, and send confirmation.

public TransactionSendResult sendMessageInTransaction(.....) SendResult = this.send(MSG); sendResult = this.send(MSG); // sendResult.getSendStatus() == SEND_OK // 2. If the message is sent successfully, Associated with the message of local affairs unit LocalTransactionState LocalTransactionState = tranExecuter. ExecuteLocalTransactionBranch (MSG, arg); This. EndTransaction (sendResult, localTransactionState, localException); }Copy the code

The endTransaction method sends a request to the broker(MQ Server) to update the final state of the transaction message:

  1. According to thesendResultfindPrepared message
  2. According to thelocalTransactionUpdates the final status of the message

If the endTransaction method fails and the data is not sent to the broker, the backcheck thread will periodically scan each table file storing transaction status (default: 1 minute). If the message has been committed or rolled back, it will be skipped. If the state is prepared may be launched an CheckTransaction request to the Producer, the Producer will call DefaultMQProducerImpl. CheckTransactionState () method to process the timer callback request broker, CheckTransactionState calls our transaction-set determination method and endTransactionOneway to update the broker with the final state of the message.

Going back to the transfer example, if The balance of Bob’s account has been reduced and the message has been successfully sent, Smith starts to consume the message, then there will be two problems: failed consumption and consumption timeout. The solution to the timeout problem is to retry until the client successfully consumes the message. The message duplication problem may occur during the whole process. Solve the problem according to the previous approach.




Consumer transaction messages

This basically solves the timeout problem, but what if the consumption fails? Ali’s solution: do it by hand. You can consider that according to the transaction process, for some reason, Smith failed to add money, need to roll back the whole process. If the messaging system were to implement this rollback process, the system would be much more complex and prone to bugs, and the probability of bugs is estimated to be much higher than the probability of consumption failure. We need to evaluate whether it is worth the expense to solve such a small problem, and this is something that people need to think about when solving difficult problems.

20160321 Added: The implementation of transaction messages was removed in version 3.2.6, so transaction messages are not supported in this release. For details, see RocketMQ issues: github.com/alibaba/Roc… Github.com/alibaba/Roc… Github.com/alibaba/Roc…

How does Producer send messages

Producer polling all queues under a topic to achieve load balancing of the sender, as shown in the following figure:




Producer Sends message load balancing

RocketMQ client send message source code:

// Construct Producer DefaultMQProducer = new DefaultMQProducer("ProducerGroupName"); // Initialize producer.start() only once during the entire application lifecycle; MSG = new Message("TopicTest1", topic "TagA",// tag = new Message("TopicTest1", topic "TagA",// tag: Custom Key, which can be used for deduplication, can be null ("Hello MetaQ").getBytes()); SendResult = producer. Send (MSG); // Clear resources, close network connections, and log off producer.shutdown();Copy the code

During the entire application lifecycle, the producer needs to call the start method to initialize the application. The main tasks of initialization are:

  1. If not specifiednamesrvThe address will be addressed automatically
  2. Start scheduled tasks: update namesRV addresses, update topic routing information from NamSRV, clean up dead brokers, send heartbeats to all Brokers…
  3. Start the load balancing service

After initialization, messages are sent. The main code for sending messages is as follows:

private SendResult sendDefaultImpl(Message msg,......) MakeSureStateOK (); // Check whether the Producer state is RUNNING this.makesureStateok (); Validators. CheckMessage (MSG, this.defaultmqProducer); / / topic routing information TopicPublishInfo TopicPublishInfo = this. TryToFindTopicPublishInfo (MSG) getTopic ()); / / select from a routing information in the message queue MessageQueue mq. = topicPublishInfo selectOneMessageQueue (lastBrokerName); SendResult = this.sendKernelImpl(MSG, MQ, communicationMode, sendCallback, timeout); sendResult = this.sendKernelImpl(MSG, MQ, communicationMode, sendCallback, timeout) }Copy the code

In the code need to focus on two methods tryToFindTopicPublishInfo and selectOneMessageQueue. Said earlier when the producer is initialized, will start timing task for routing information and update to the local cache, so tryToFindTopicPublishInfo will first topic routing information was obtained from the cache, if there is no access to, will own namesrv obtain routing information. The selectOneMessageQueue method returns a queue through polling to achieve load balancing.

If the Producer fails to send a message, the Producer automatically tries again. The retry policy is as follows:

  1. Retry times < retryTimesWhenSendFailed (configurable)
  2. Total time (including n retries) < sendMsgTimeout (the parameter passed when sending the message)
  3. If both conditions are met, Producer selects another queue to send messages
5. Message storage

RocketMQ’s message storage is a combination of consume Queue and commit log.

1, Consume the Queue

Consume Queue is a logical queue of messages, equivalent to the directory of dictionaries, used to specify the location of messages in the physical file Commit log.

We can consumequeue and commitlog storage directory specified in the configuration Each queue under each topic has a corresponding consumequeue files, such as:

${rocketmq.home}/store/consumequeue/${topicName}/${queueId}/${fileName}Copy the code

Consume Queue file organization, as shown in the figure:




Consume Queue file organization diagram

  1. According to thetopicandqueueIdTopicA and QueueId=0 form a ConsumeQueue, TopicA and QueueId=1 form a ConsumeQueue.
  2. On the consumer sideGroupNameIf the consumer fails to consume, the message will be sent to the retry queue, as shown in the figure%RETRY%ConsumerGroupA.
  3. On the consumer sideGroupNameTo group the dead letter queue, if the consumer fails to consume, and retry the specified number of times, it still fails to send to the dead letter queue, such as the figure%DLQ%ConsumerGroupA.

Dead Letter queues are generally used to store messages that cannot be delivered for some reason, such as messages that failed to be processed or have expired.

Consume Queue The storage unit in Consume Queue is a binary data of fixed length of 20 bytes, which is written and read in sequence, as shown in the following figure:




Consumequeue Format of the file storage unit

  1. CommitLog Offset refers to the actual Offset of the message in the CommitLog file
  2. Size Size of the message in the store
  3. Message Tag HashCode The hash value of the Tag that stores the Message. It is used for Message filtering when subscribeing (if a Tag is specified, the subscribed Message will be found using HashCode).
2, the Commit Log

CommitLog: A physical file where messages are stored. Commitlogs on each broker are shared among all queues on the host without distinction. The default location of the file is as follows, which can still be modified through the configuration file:

${user.home} \store\${commitlog}\${fileName}Copy the code

The length of the message storage unit is not fixed. Files are written in sequence and read randomly. The storage structure of messages is shown in the following table. Messages are stored in sequence according to the number sequence and corresponding contents.




Commit Log Storage unit structure diagram

3. Message storage implementation

Message storage implementation, more complex, but also worth understanding, will be written separately later analysis, this section only code to explain the specific process.

// Set the storage time msg.setStoreTimestamp(System.currentTimeMillis()); // Set the message body BODY CRC (consider the most appropriate setting msg.setBodyCRC(UtilAll.crc32(msg.getBody())); StoreStatsService storeStatsService = this.defaultMessageStore.getStoreStatsService(); synchronized (this) { long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now(); // Here settings are stored timestamp, in order to ensure an orderly global msg.setStoreTimestamp(beginLockTimestamp); / / MapedFile: physical file in memory mapping, and the memory data persistence to physical file MapedFile MapedFile = this. MapedFileQueue. GetLastMapedFile (); / / the Message is appended to the file commitlog result. = mapedFile appendMessage (MSG, enclosing appendMessageCallback); switch (result.getStatus()) { case PUT_OK:break; case END_OF_FILE: // Create a new file, re-write the message mapedFile = this.mapedFileQueue.getLastMapedFile(); result = mapedFile.appendMessage(msg, this.appendMessageCallback); break; DispatchRequest dispatchRequest = new DispatchRequest( topic,// 1 queueId,// 2 result.getWroteOffset(),// 3 result.getWroteBytes(),// 4 tagsCode,// 5 msg.getStoreTimestamp(),// 6 result.getLogicsOffset(),// 7 msg.getKeys(),// 8 /** * Transaction */ msg.getSysFlag(),// 9 msg.getPreparedTransactionOffset()); // 10 // 1. Distribute the message location to ConsumeQueue // 2. Distributed to IndexService index this. DefaultMessageStore. PutDispatchRequest (dispatchRequest); }Copy the code
4. Index files for messages

If a message contains a key value, an IndexFile is used to store the message index.




Message index

Index files are mainly used to query messages by key, and the flow is mainly as follows:

  1. SlotNum is the maximum number of slots in an index file, such as slotNum=5000000.
  2. Find the last item in the index list based on slotValue(slotValue always points to the last item in the index list)
  3. Traversing the index list returns the result set within the query time range (default maximum of 32 records returned at one time)
Message subscription

RocketMQ message subscription has two modes. One is Push mode, where MQServer actively pushes to the consumer; The other is the Pull mode, where the consumer takes the initiative to Pull from the MQServer when needed. But in the concrete implementation, Push and Pull modes are adopted by the consumer side to actively Pull.

Let’s start with load balancing on the consumer side:




Load balancing on the consumer side

The consumer uses the RebalanceService thread to load all queues on a topic every 10 seconds:

  1. Iterate over all topics under Consumer and subscribe to all messages based on topic
  2. Get all consumers under the same topic and Consumer Group
  3. Then, the consumption queue is allocated according to specific allocation policies, including: average allocation, consumer configuration, etc

As shown above: If there are five queues and two consumers, then the first consumer consumes three queues and the second consumer consumes two queues. This is an equal allocation strategy, which is similar to our pagination, where all queues under a TOPIC are records, and the number of consumers is equal to the total number of pages, so the number of records per page is similar to which queues a Consumer will consume.

Through such a strategy to achieve the average consumption in general, such a design can also greatly expand the level of consumers to improve the consumption ability.

The Push mode on the consumer side is implemented through the long polling mode, as shown below:




Schematic diagram of Push mode

The Consumer sends Pull requests to the broker at regular intervals. The broker immediately returns data if it receives a Pull request. The Consumer calls back the Listener method set by the Consumer after receiving the returned message. If there is no data in the message queue when a Pull request is received, the broker will block the request until there is data delivery or a timeout.

Of course, the Consumer side uses a thread to send the PullRequest from the blocking queue LinkedBlockingQueue to the broker pull message to prevent the Consumer from blocking uniformly. The Broker, on the other hand, will cache the Consumer PullRequest into the ConcurrentHashMap if it receives no PullRequest. The broker starts a thread to pull PullRequest checks from ConcurrentHashMap until data is returned.

Other features of RocketMQ

The front of the six features are basically all point to point, want to understand, but also need to look at the source code, many in practice. In addition to the features already mentioned, RocketMQ also supports:

  1. Timing of the message
  2. Flush policy for messages
  3. Active synchronization policy: Synchronous dual-write and asynchronous replication
  4. Mass message accumulation ability
  5. Efficient communication
  6. .

Many of the design ideas and solutions involved are worth further study:

  1. Message storage design: not only to meet the accumulation capacity of massive messages, but also to meet the very fast query efficiency, but also to ensure the efficiency of writing.
  2. Efficient communication component design: High throughput, millisecond message delivery capability are all dependent on efficient communication.
  3. .

RocketMQ Best practices

I. Producer best practices

1. An application should use a Topic as much as possible. Subtypes of messages are identified by tags, which can be set freely by the application. Tags can only be used to filter messages at the broker when a consumer subscribes to a message if the sent message is set to tags. 2. Set the unique identifier of each message at the business level to the keys field for locating message loss problems in the future. Since it is a hash index, it is important to ensure that the key is as unique as possible to avoid potential hash conflicts. 3. Sendresult and key fields must be printed to print message logs if the message is sent successfully or fails. 4, for the message can not lose application, must have a message retransmission mechanism. For example, if a message fails to be sent and is stored in a database, a scheduled program can try to resend it or manually trigger it. 5. If some applications do not care whether the message is sent successfully, send the message directly using sendOneWay.

Consumer best practices

1. The consumption process should be idempotent (i.e., the consumption end should be de-weighted). 2. Optimize the process of consuming each message

Other configurations

AutoCreateTopicEnable should be turned off online, that is, set to false in the configuration file.

When RocketMQ sends a message, it first gets the routing information. If it is a new message, since no Topic has been created on MQServer, this configuration, if turned on, will return routing information for the default Topic (RocketMQ creates a Topic named TBW102 on each broker). The Producer then selects a Broker to send the message. When the selected Broker stores the message and finds that the topic for the message has not yet been created, it automatically creates a topic. As a result, all future messages from this TOPIC will be sent to this broker, failing to achieve load balancing.

Therefore, based on the current design of RocketMQ, it is recommended to turn off automatic creation of topics and then manually create topics based on the size of the message volume.

RocketMQ design related

RocketMQ is designed based on the following assumptions:

Every PC can go down and become unserviceable any cluster can run out of processing capacity. At worst, the Intranet environment requires low latency to provide the best user experience

RocketMQ’s key design:

Distributed Clustering strong Data Security Massive data accumulation Millisecond delivery delay (push-pull mode)

This is what RocketMQ was designed to assume and achieve. I think these assumptions apply to all system designs. With the increase of our system services, each developer should pay attention to their procedures whether there is a single point of failure, if the failure should be how to recover, can be very good level expansion, external interface is efficient enough, their management data is safe enough…… In order to develop efficient and robust programs, we can standardize our design more.

Appendix: RocketMQ terminology and an introduction to the overall architecture

RocketMQ terminology

Topic refers to the first-level type of message. For example, the message of an e-commerce system can be divided into transaction message and logistics message…… A message must have a Topic.

Tag Indicates the second-level type of a message. For example, a transaction message can be divided into the following types: transaction creation message and transaction completion message….. A message can have no Tag. RocketMQ provides level 2 message classification for flexible control.

Queue We can set up multiple queues within a topic. When we send a message, we need to specify the topic for the message. RocketMQ polls all queues under that topic to send messages out.

Producer and Producer Group Producer indicates the Producer of the message queue. The nature of message queues is that the publish-subscribe pattern is implemented, with producers producing messages and consumers consuming messages. So the term Producer is used to produce and send messages, generally referring to a business system.

An Producer Group is the name of a set of producers that generally send one kind of message and send it logically.

Consumer and Consumer Group Message consumers, usually asynchronously consumed by the background system.

An application usually registers a Listener interface with a Consumer object. As soon as it receives a message, the Consumer object immediately calls back the Listener interface method. Pull Consumer A type of Consumer, the application usually actively invokes the Consumer’s Pull message method to Pull messages from the Broker.

A Consumer Group is a collection name for a class of consumers that typically consume a type of message with consistent consumption logic.

Broker A Broker that stores and forwards messages. It can be understood as a message queue server, which provides messages receiving, storing, pulling and forwarding services. The broker is at the heart of RocketMQ and cannot be hung, so it needs to be highly available.

Broadcast consumption A message is consumed by multiple consumers, even if they belong to the same Consumer Group, the message is consumed by each Consumer in the Consumer Group once. The concept of Consumer Group in broadcast consumption can be considered meaningless in terms of message partitioning.

Clustered consumption Consumer instances in a Consumer Group share consumption messages equally. For example, if a Topic has nine messages and a Consumer Group has three instances (perhaps three processes, or three machines), each instance consumes only three of the messages.

NameServer NameServer is a name service that provides two functions:

  1. receivebrokerRequest for registrationbrokerRouting information of
  2. interfaceclientAccording to atopicGet its tobrokerRouting information of

    NameServerThere is no state and you can scale horizontally. eachbrokerIt will arrive at boot timeNameServerRegistration;ProducerBefore sending a messagetopictoNameServerGet the route (tobroker) information;ConsumerIt is also obtained periodicallytopicRouting information.
Second, the RocketMQ Overview



rocketmq overview

A Producer sends messages in turn to a set of queues called topics. If a Consumer consumes a broadcast, a Consumer instance consumes all queues corresponding to the Topic. In the case of cluster consumption, multiple Consumer instances average the collection of queues corresponding to this Topic.

Take a look at the RocketMQ physical deployment structure:




RocketMQ network deployment diagram

RocketMQ network deployment features:

  1. Name ServerIs a nearly stateless node that can be clustered and no information is synchronized between nodes.
  2. Broker deployment is relatively complex, and brokers are divided intoMasterwithSlave, aMasterYou can have multipleSlaveBut aSlaveThere can only be oneMaster.MasterwithSlaveBy specifying the sameBrokerName, differentBrokerIdTo define,BrokerId=0saidMaster, non-0 indicatesSlave.MasterYou can deploy more than one. eachBrokerwithName ServerEstablish a long-term connection between all nodes in the cluster and register them periodicallyTopicInformation to allName Server.
  3. ProducerwithName ServerOne of the nodes in the cluster (randomly selected) establishes a long connection, periodically fromName ServerObtain Topic routing information, establish a long connection to the Master that provides Topic services, and periodically send heartbeat messages to the Master. Producer is stateless and can be deployed in a cluster.
  4. ConsumerwithName ServerOne of the nodes in the cluster (randomly selected) establishes a long connection, periodically fromName ServerTake the Topic routing information and provide itTopicThe Master and Slave of the service establish a long connection and periodically send heartbeat messages to the Master and Slave.ConsumerMessages can be subscribed from either Master or Slave, and the subscription rules are determined by the Broker configuration.
Other reference materials

Note: the level is limited, unavoidable omission, if the question please leave a message