Learning any technology is a two-step process:
-
Setting up the environment
-
helloworld
I'm no exception. I'll do it directly.
1, RocketMQ installation
1. Documents
Official website
http://rocketmq.apache.org
GitHub
https://github.com/apache/rocketmq
2. Download
wget https://mirror.bit.edu.cn/apache/rocketmq/4.7.0/rocketmq-all-4.7.0-bin-release.zip
We are based on Centos8 and are learning from official documents, so the download address is also official.
Go to the official website to find the right version to download. At present, my latest version here is version 4.7.0.
http://rocketmq.apache.org/dowloading/releases/
https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.7.0/rocketmq-all-4.7.0-bin-release.zip
3. Preparations
3.1 decompression
unzip rocketmq-all-4.7.0-bin-release.zip
3.2. Install jdk
sudo yum install java-1.8.0-openjdk-devel
4. Start
4.1. Start namesrv
cd rocketmq-all-4.7.0-bin-release/bin
./mqnamesrv
4.2 start broker
cd rocketmq-all-4.7.0-bin-release/bin
./mqbroker -n localhost:9876
Common errors and solutions:
Common error: failed to start broker Cannot allocate memory
[root@node-113b bin]# ./mqbroker -n localhost:9876
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000005c0000000, 8589934592, 0) failed
; error='Cannot allocate memory' (errno=12)#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 8589934592 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /usr/local/rocketmq/bin/hs_err_pid1997.log
Solution:
Because the default memory allocation is too large, it exceeds the local memory and directly OOM.
Modify the following two scripts in bin / directory
runbroker.sh
runserver.sh
Search for - server -Xms in both scripts, allocate its memory a little bit, 512MB will be enough if you play by yourself, enough!
4.3. Startup success identification
namesrv start success id:
broker start success id:
2, Installation of RocketMQ console
At present, there are two ways to obtain the console:
-
Third party websites to download off the shelf, such as csdn.
-
The official source code package is compiled by itself. There is no official one.
Of course, we take an official approach here.
1. Official documents
github warehouse
https://github.com/apache/rocketmq-externals
Chinese guide
https://github.com/apache/rocketmq-externals/blob/master/rocketmq-console/doc/1_0_0/UserGuide_CN.md
2. Download source code
https://codeload.github.com/apache/rocketmq-externals/zip/master
3. Modify configuration (optional)
After downloading and decompressing, the file directory is as follows:
Modify rocketmq consolesrcmain resourcesapplication.properties Documented server.port That's it. The default is 8080.
4. Compile package
Enter rocketmq console, and compile and package with maven
mvn clean package -DskipTests
After packaging, we will generate our spring boot jar program under target, and directly start Java jar.
5. Launch console
Throw the compiled and packaged springboot program onto the server, and execute the following command to start it
java -jar rocketmq-console-ng-1.0.1.jar --rocketmq.config.namesrvAddr=127.0.0.1:9876
If you want to start in the background, nohup&
Visit to see the effect:
3, Testing
rocketmq provides us with testing tools and classes, which can be easily tested after installation.
0. Preparation
The default testing tool provided by rocketmq is in bin directory, which is called tools.sh . Before testing, we need to configure this script and specify the namesrv address for it. Otherwise, when testing sending / consuming messages, the following error will appear: connect to null failed:
22:49:02.470 [main] DEBUG i.n.u.i.l.InternalLoggerFactory - Using SLF4J as the default logging framework
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
java.lang.IllegalStateException: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to null failed
The configuration is as follows:
vim tools.sh
#In export Java_ Add the following code to home
export NAMESRV_ADDR=localhost:9876
1. Send message
./tools.sh org.apache.rocketmq.example.quickstart.Producer
If it succeeds, you will see the log of the crash, because this class will send 1000 messages to the Topic of TopicTest.
2. Consumer News
./tools.sh org.apache.rocketmq.example.quickstart.Consumer
If it is successful, you will see the log of the crash, because this class will consume all the messages under the TopicTest. The 1000 just sent will be consumed.
3. Console
After sending successfully, we can naturally come to the control console to see the information, consumption and so on
4, Architecture and roles
1. Architecture diagram
2. Role
2.1,Broker
-
Understood as RocketMQ itself
-
broker is mainly used for producer and consumer to receive and send messages
-
broker will regularly submit its own information to nameserver
-
It is the message storage and forwarding server of message middleware
-
When each Broker node starts, it will traverse the NameServer list, establish a long connection with each NameServer, register its own information, and then report regularly
2.2,Nameserver
-
It's understood as the effect of zookeeper, but instead of using zk, he wrote a nameserver to replace zk
-
The bottom layer is implemented by netty, which provides the functions of route management, service registration and service discovery. It is a stateless node
-
Nameserver is a service discoverer. All roles in the cluster (producer, broker, consumer, etc.) need to report their status to nameserver regularly, so that they can discover each other. If they don't report after the timeout, nameserver will remove them from the list
-
nameserver can deploy multiple. When multiple nameservers exist, other roles report information to them at the same time to ensure high availability,
-
NameServer clusters do not communicate with each other, and there is no concept of active and standby
-
Nameserver is stored in memory. Information such as broker and topic in nameserver will not be persisted by default, so it is a stateless node
2.3,Producer
-
Producer of message
-
Randomly select one of the NameServer nodes to establish a long connection to obtain topic routing information (including the queues under topic, which broker s these queues are distributed on, etc.)
-
Next, establish a long connection to the master providing the topic service (because rocketmq can only write messages to the master), and send the heartbeat to the master regularly
2.4,Consumer
-
Consumers of messages
-
Get the routing information of the Topic through the NameServer cluster, and connect to the corresponding Broker to consume messages
-
Since both Master and Slave can read messages, the Consumer will establish a connection with both Master and Slave to consume messages
3. Core process
-
All brokers are registered on Nameserver
-
When Producer sends a message, it will get the topic information of the message from the Nameserver
-
Producer establishes a long connection to all masters providing services, and sends heartbeat to the master regularly
-
Consumer obtains the routing information of Topic through NameServer cluster
-
The Consumer will establish a connection with all masters and all slaves to listen for new messages
5, Core concepts
1,Message
Message carrier. Topic must be specified when message is sent or consumed. Message has an optional Tag entry for filtering messages, and additional key value pairs can be added.
2,topic
The logical classification of messages. Before sending a message, you must specify a topic to send it. That is, send the message to this topic. This topic is specified for consumption when consuming messages. It's logical classification.
3,queue
One topic will be divided into N queues, and the number is configurable. Message itself is actually stored on the queue, and what consumers consume is also the message on the queue. Say more, for example, if a topic has four queues and five consumers are consuming the topic, then one consumer will be wasted. Because of the load balancing strategy, each consumer consumes one queue, 5 > 4, and overflows one. This will not work.
4,Tag
Tag is a further subdivision of Topic. As the name implies, tag. Each message can be tagged when it is sent. When it is consumed, it can be filtered according to the tag and consumed selectively.
5,Message Model
Message model: Clustering and Broadcasting
6,Message Order
Message order: order and concurrency
7,Producer Group
Message producers group
8,Consumer Group
Message consumer group
6, ACK
First of all, make it clear that the ACK mechanism is on the Consumer side, not the Producer side. That is to say, the Consumer needs to confirm the ACK after consuming the message. If the message is not confirmed, it means that the consumption fails. At this time, the Broker will try again (only in cluster mode). The meaning of ACK is: the Consumer said: ok, I succeeded in consumption. Mark this message as consumed.
7, Consumption mode
1. Clustering mode
1.1 diagram
1.2 characteristics
-
Each message only needs to be processed once, and the broker will only send the message to one consumer in the consumption cluster
-
Routing to the same machine cannot be guaranteed during message replay
-
Consumption status maintained by broker
2. Broadcasting mode
2.1 diagram
2.2 characteristics
-
Consumption progress is maintained by consumer
-
Ensure that every consumer consumes a message
-
The message of consumption failure will not be re invested
8, Java API
explain:
-
RocketMQ server version is the latest version: 4.7.0
-
The latest version of Java client: 4.7.0
pom is as follows
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.7.0</version>
</dependency>
1,Producer
The following conditions are necessary for sending messages:
-
Specify production group name (cannot use default, error will be reported)
-
Configure namesrv address (required)
-
Specify topic name (required)
-
Specify tag/key (optional)
Verify whether the message is sent successfully: after sending the message, you can start the consumer to consume, or you can go to the control console to see whether the message exists.
1.1 send (synchronous)
public class Producer {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
//Create a message object with topic of myTopic001 and message content of hello world
Message msg = new Message("myTopic001", "hello world".getBytes());
//Send message to mq, synchronous
SendResult result = producer.send(msg);
System.out.println("Message sent successfully! result is : " + result);
//Close Producer
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Message sent successfully! result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854140F418B4AAC26F7973910000, offsetMsgId=7B39B49D00002A9F00000000000589BE, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=0], queueOffset=7]
Producer shutdown!
1.2 send (batch)
public class ProducerMultiMsg {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
String topic = "myTopic001";
//Create a message object. The topic is myTopic001 and the message content is hello world1/2/3
Message msg1 = new Message(topic, "hello world1".getBytes());
Message msg2 = new Message(topic, "hello world2".getBytes());
Message msg3 = new Message(topic, "hello world3".getBytes());
//Create a collection of message objects for bulk sending
List<Message> msgs = new ArrayList<>();
msgs.add(msg1);
msgs.add(msg2);
msgs.add(msg3);
//The api of batch sending is also send(), but its overload method supports list < message >, which is also synchronous sending.
SendResult result = producer.send(msgs);
System.out.println("Message sent successfully! result is : " + result);
//Close Producer
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Message sent successfully! result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854139C418B4AAC26F7D13770000,A9FE854139C418B4AAC26F7D13770001,A9FE854139C418B4AAC26F7D13770002, offsetMsgId=7B39B49D00002A9F0000000000058A62,7B39B49D00002A9F0000000000058B07,7B39B49D00002A9F0000000000058BAC, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=0], queueOffset=8]
Producer shutdown!
It can be seen from the result that there is only one msgId, so it can be found that although there are three message objects, they are only sent once, which greatly saves the cost of client and server.
Error condition:
The topic for batch sending must be the same. If the message object specifies different topics, an error will be reported during batch sending:
Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: Failed to initiate the MessageBatch
For more information, please visit the url, http://rocketmq.apache.org/docs/faq/
at org.apache.rocketmq.client.producer.DefaultMQProducer.batch(DefaultMQProducer.java:950)
at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:898)
at com.chentongwei.mq.rocketmq.ProducerMultiMsg.main(ProducerMultiMsg.java:29)
Caused by: java.lang.UnsupportedOperationException: The topic of the messages in one batch should be the same
at org.apache.rocketmq.common.message.MessageBatch.generateFromList(MessageBatch.java:58)
at org.apache.rocketmq.client.producer.DefaultMQProducer.batch(DefaultMQProducer.java:942)
... 2 more
1.3 sendCallBack (asynchronous)
public class ProducerASync {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
//Create a message object with the topic of myTopic001 and the message content of hello world async
Message msg = new Message("myTopic001", "hello world async".getBytes());
//Send asynchronously and get the result of sending through SendCallback interface
producer.send(msg, new SendCallback() {
//Send successful callback interface
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("Message sent successfully! result is : " + sendResult);
}
//Send failed callback interface
@Override
public void onException(Throwable throwable) {
throwable.printStackTrace();
System.out.println("Failed to send message! result is : " + throwable.getMessage());
}
});
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Producer shutdown!
java.lang.IllegalStateException: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed
at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:681)
at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:511)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.tryToFindTopicPublishInfo(DefaultMQProducerImpl.java:692)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:556)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.access$300(DefaultMQProducerImpl.java:97)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl$4.run(DefaultMQProducerImpl.java:510)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed
at org.apache.rocketmq.remoting.netty.NettyRemotingClient.getAndCreateNameserverChannel(NettyRemotingClient.java:441)
at org.apache.rocketmq.remoting.netty.NettyRemotingClient.getAndCreateChannel(NettyRemotingClient.java:396)
at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:365)
at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1371)
at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1361)
at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:624)
... 10 more
Failed to send message! result is : org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to [124.57.180.156:9876] failed
Why is the report wrong? It's very simple. It's asynchronous. It can be seen from the results. Since it's asynchronous, I haven't sent it to mq yet. You should shut it down first. Definitely not, so we'll sleep for 1s before shutdown to see the effect
public class ProducerASync {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
//Create a message object with the topic of myTopic001 and the message content of hello world async
Message msg = new Message("myTopic001", "hello world async".getBytes());
//Send asynchronously and get the result of sending through SendCallback interface
producer.send(msg, new SendCallback() {
//Send successful callback interface
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("Message sent successfully! result is : " + sendResult);
}
//Send failed callback interface
@Override
public void onException(Throwable throwable) {
throwable.printStackTrace();
System.out.println("Failed to send message! result is : " + throwable.getMessage());
}
});
Thread.sleep(1000);
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Message sent successfully! result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854106E418B4AAC26F8719B20000, offsetMsgId=7B39B49D00002A9F0000000000058CFC, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=1], queueOffset=2]
Producer shutdown!
1.4,sendOneway
public class ProducerOneWay {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
//Create a message object with topic of myTopic001 and message content of hello world oneway
Message msg = new Message("myTopic001", "hello world oneway".getBytes());
//It's the most efficient because oneway doesn't care whether it's successful or not. I don't care if it's delivered. So the return is void
producer.sendOneway(msg);
System.out.println("Message delivered successfully! , note that this is a successful delivery, not a successful message! Because of me sendOneway I don't know if it's successful or not. I didn't return the value.");
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Message delivered successfully! , note that this is a successful delivery, not a successful message! Because I sendOneway didn't know whether it was successful or not. I didn't return the value.
Producer shutdown!
1.5 efficiency comparison
Sendoneway > sendcallback > send batch > send single
It's easy to understand that sendOneway doesn't ask for results, and I'll be responsible for delivery. Whether you fail or succeed, I'm equivalent to a transfer station. When you come, I'll throw it out, and I won't do anything else. So the fastest.
And sendCallBack is that asynchronous sending is certainly more efficient than synchronous sending.
The efficiency of send batch and send single can also be divided into different situations. If there is only one msg to be sent, then gross batch will be carried out and send single will be completed directly.
2,Consumer
Each consumer can only focus on one topic.
The following conditions are necessary for sending messages:
-
Specify consumption group name (cannot use default, error will be reported)
-
Configure namesrv address (required)
-
Specify topic name (required)
-
Specify tag/key (optional)
2.1,CLUSTERING
Cluster mode, default.
For example, after starting five consumers and Producer produces a message, Broker will choose one of the five consumers to consume the message, so it belongs to the point-to-point consumption mode.
public class Consumer {
public static void main(String[] args) throws Exception {
//Specify the name of the consumption group as my consumer
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("my-consumer");
//Configure namesrv address
consumer.setNamesrvAddr("124.57.180.156:9876");
//Subscribe to topic: all messages under myTopic001 (because it is *, * specifies the tag tag, which represents all messages without any filtering)
consumer.subscribe("myTopic001", "*");
//Register the listener for message messages.
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg : msgs) {
String str = new String(msg.getBody());
//Output message content
System.out.println(str);
}
//By default, this message will only be consumed by one consumer, which is called point-to-point consumption mode. That is cluster mode.
//ack confirmation
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//Launch consumer
consumer.start();
System.out.println("Consumer start");
}
}
2.2,BROADCASTING
Broadcast mode.
For example, when five consumers are started and a Producer produces a message, the Broker will broadcast the message to five consumers. Each of the five consumers will consume the message once.
//Just add the following sentence to the code:
consumer.setMessageModel(MessageModel.BROADCASTING);
2.3 comparison of two modes
-
By default, the cluster is the default, and the broadcast mode needs to be configured manually.
-
One message: multiple consumers in cluster mode only have one Consumer consumption. Every Consumer in broadcast mode consumes this message.
-
In the broadcast mode, after sending a message, it will be consumed by all the consumers currently being broadcast, but the newly added consumers will not consume the message. It's easy to understand that: the village's loudspeakers shout the whole village to get the eggs, and the next day your village's new comer will not hear the news of yesterday's loudspeakers.
3,TAG&&KEY
When sending / consuming messages, you can specify tag/key to filter messages. Wildcards are supported. *Represents the consumption of all messages under this topic without filtering.
look down org.apache.rocketmq.common.message.Message The source code can find that when sending messages, you can specify tag s and keys:
public Message(String topic, String tags, String keys, byte[] body) {
this(topic, tags, keys, 0, body, true);
}
For example:
public class ProducerTagsKeys {
public static void main(String[] args) throws Exception {
//Specify the production group name as my producer
DefaultMQProducer producer = new DefaultMQProducer("my-producer");
//Configure namesrv address
producer.setNamesrvAddr("124.57.180.156:9876");
//Start Producer
producer.start();
//Create a message object with topic of myTopic001, message content of hello world, tags of test tags and keys of test keys
Message msg = new Message("myTopic001", "test-tags", "test-keys", "hello world".getBytes());
//Send message to mq, synchronous
SendResult result = producer.send(msg);
System.out.println("Message sent successfully! result is : " + result);
//Close Producer
producer.shutdown();
System.out.println("producer shutdown!");
}
}
Output results:
Message sent successfully! result is : SendResult [sendStatus=SEND_OK, msgId=A9FE854149DC18B4AAC26FA4B7200000, offsetMsgId=7B39B49D00002A9F0000000000058DA6, messageQueue=MessageQueue [topic=myTopic001, brokerName=broker-a, queueId=3], queueOffset=3]
Producer shutdown!
By viewing the control console, you can see that the tags and keys have taken effect:
If * is specified during consumption, it is all the messages under this topic. We can specify prefix wildcards, such as:
//In this way, only messages with the tag beginning with test - * under myTopic001 will be consumed.
consumer.subscribe("myTopic001", "test-*");
//Represents all messages with tag a or TagB under subscription Topic myTopic001
consumer.subscribe("myTopic001", "TagA||TagB");
It also supports SQL expression filtering, which is not very common. No BB.
4. Common errors
4.1,sendDefaultImpl call timeout
4.1.1 abnormality
Exception in thread "main" org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:666)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1342)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1288)
at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:324)
at com.chentongwei.mq.rocketmq.Producer.main(Producer.java:18)
4.1.2 solution
1. If you are a cloud server, first check whether the security group allows 9876 port access, whether the firewall is enabled, and whether 9876 is mapped out if it is enabled.
2. Modify the configuration file broker.conf , plus:
brokerIP1 = I use alicloud server, here is my public IP
When starting namesrv and broker, add the local IP (I use alicloud server, here is my public IP):
./bin/mqnamesrv -n IP:9876
./bin/mqbroker -n IP:9876 -c conf/broker.conf
4.2,No route info of this topic
4.2.1 abnormality
Exception in thread "main" org.apache.rocketmq.client.exception.MQClientException: No route info of this topic: myTopic001
See http://rocketmq.apache.org/docs/faq/ for further details.
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:684)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1342)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1288)
at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:324)
at com.chentongwei.mq.rocketmq.Producer.main(Producer.java:18)
4.2.2 solution
It's obvious that the transmission is successful. It's no longer the timeout just now, but it tells us that we don't have this topic. It can't be created manually every time, so when starting broker, you can specify parameters to let broker create automatically for us. as follows
./bin/mqbroker -n IP:9876 -c conf/broker.conf autoCreateTopicEnable=true