Apache RocketMQ: understand the official OrderExample example

Keywords: Apache

1. Declaration

The current content is mainly to learn and analyze the official OrderExample example and understand its meaning. Refer to Official documents

2. Official demo

Serial number message producer

public class OrderedProducer {
	public static void main(String[] args) throws Exception {
		// Instantiate with a producer group name.
		DefaultMQProducer producer = new DefaultMQProducer("example_group_name");
		producer.setNamesrvAddr("192.168.1.102:9876");
		// Launch the instance.
		producer.start();
		// String[] tags = new String[] { "TagA" };
		for (int i = 0; i < 10; i++) {
			int orderId = i;
			// Create a message instance, specifying topic, tag and message body.
			System.out.println("orderId==>" + orderId + ",i=" + i);
			Message msg = new Message("TopicTestjjj", "TagA", "KEY" + i,
					("Hello RocketMQ i=" + i + ",orderId=" + orderId).getBytes(RemotingHelper.DEFAULT_CHARSET));
			// The so-called sending an orderly message is to pass the serial number when sending the message. Select the message queue to send
			SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
				@Override
				public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {

					Integer id = (Integer) arg;
					int index = id % mqs.size();

					// The number of message queues is 4
					System.out.println("mqs Size of==>" + mqs.size());
					// Send messages to only one message queue
					return mqs.get(index);
				}
				// The arg object passed here is the sequence number
			}, orderId);

			System.out.printf("%s%n", sendResult);
		}
		// server shutdown
		producer.shutdown();
	}
}

Serial number message consumer

public class OrderedConsumer {
	public static void main(String[] args) throws Exception {
		// Push consumption pattern
		DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test2");
		// Pull consumer model
		// DefaultMQPullConsumer consumer =new DefaultMQPullConsumer(consumerGroup)
		consumer.setNamesrvAddr("192.168.1.102:9876");

		// Set where consumer consumption messages start
		consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

		// Represents a subscription to a message in TopicTestjjj with a specific tag
		consumer.subscribe("TopicTestjjj", "TagA");

		MessageListenerOrderly listenerOrderly = new MyMessageListenerOrderly();
		consumer.registerMessageListener(listenerOrderly);

		consumer.start();

		System.out.printf("Consumer Started.%n");
	}

	static class MyMessageListenerOrderly implements MessageListenerOrderly {
		AtomicLong consumeTimes = new AtomicLong(0);

		@Override
		public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
			// Turn off auto submit
			context.setAutoCommit(false);

			for (MessageExt msgExt : msgs) {
				try {
					String msg = new String(msgExt.getBody(), RemotingHelper.DEFAULT_CHARSET).intern();
					System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msg + "%n");
				} catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			long incrementAndGet = this.consumeTimes.incrementAndGet();
			System.out.println("Current consumption times:" + incrementAndGet);
			return ConsumeOrderlyStatus.SUCCESS;

		}

	}
}

General consumers

public class Consumer {

    public static void main(String[] args) throws InterruptedException, MQClientException {

        // Instantiate with specified consumer group name.
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test");
		/*
		 * consumer.getDefaultMQPushConsumerImpl().getmQClientFactory().getMQAdminImpl()
		 */
        // Specify name server addresses.
        consumer.setNamesrvAddr("192.168.1.102:9876");

        // Subscribe one more more topics to consume.
        consumer.subscribe("TopicTestjjj", "*");
        // Register callback to execute on arrival of messages fetched from brokers.
        consumer.registerMessageListener(new MessageListenerConcurrently() {

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                ConsumeConcurrentlyContext context) {
                //System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
                for (MessageExt messageExt : msgs) {
                	try {
						String msg = new String(messageExt.getBody(),RemotingHelper.DEFAULT_CHARSET).intern();
						System.out.println("Receive New Messages: "+msg);
					} catch (UnsupportedEncodingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });

        //Launch the consumer instance.
        consumer.start();

        System.out.printf("Consumer Started.%n");
    }
}

The above mainly distinguishes whether the consumption is in order mode through messagelistener concurrent and messagelistener ordered

The main means of consumption are: the server pushes messages to consumers

The order consumer manually sends messages to four messagequeues, and the orderId is in order

The actual messages should be distributed like this (the message is FIFO)

3. Test

1. Start ordinary consumers first, then order consumers, and finally order producers. The results are as follows:

General consumers:

Receive New Messages: Hello RocketMQ i=9,orderId=9
Receive New Messages: Hello RocketMQ i=5,orderId=5
Receive New Messages: Hello RocketMQ i=1,orderId=1
Receive New Messages: Hello RocketMQ i=0,orderId=0
Receive New Messages: Hello RocketMQ i=4,orderId=4
Receive New Messages: Hello RocketMQ i=8,orderId=8
Receive New Messages: Hello RocketMQ i=3,orderId=3
Receive New Messages: Hello RocketMQ i=7,orderId=7
Receive New Messages: Hello RocketMQ i=2,orderId=2
Receive New Messages: Hello RocketMQ i=6,orderId=6

order consumers are:

ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=0,orderId=0
ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=1,orderId=1
 Current consumption times: 1
 Current consumption times: 2
ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=4,orderId=4
ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=5,orderId=5
 Current consumption times: 3
 Current consumption times: 4
ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=8,orderId=8
ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=9,orderId=9
 Current consumption times: 5
 Current consumption times: 6
ConsumeMessageThread_3 Receive New Messages: Hello RocketMQ i=3,orderId=3
 Current consumption times: 7
ConsumeMessageThread_4 Receive New Messages: Hello RocketMQ i=2,orderId=2
ConsumeMessageThread_3 Receive New Messages: Hello RocketMQ i=7,orderId=7
 Current consumption times: 8
 Current consumption times: 9
ConsumeMessageThread_4 Receive New Messages: Hello RocketMQ i=6,orderId=6
 Current consumption times: 10

It seems that current order consumers spend more (almost two at a time)

2. Start the order producer again:
Ordinary consumers:

Receive New Messages: Hello RocketMQ i=0,orderId=0
Receive New Messages: Hello RocketMQ i=1,orderId=1
Receive New Messages: Hello RocketMQ i=2,orderId=2
Receive New Messages: Hello RocketMQ i=3,orderId=3
Receive New Messages: Hello RocketMQ i=4,orderId=4
Receive New Messages: Hello RocketMQ i=5,orderId=5
Receive New Messages: Hello RocketMQ i=6,orderId=6
Receive New Messages: Hello RocketMQ i=7,orderId=7
Receive New Messages: Hello RocketMQ i=8,orderId=8
Receive New Messages: Hello RocketMQ i=9,orderId=9

order consumer:

ConsumeMessageThread_5 Receive New Messages: Hello RocketMQ i=0,orderId=0
 Current consumption times: 11
ConsumeMessageThread_6 Receive New Messages: Hello RocketMQ i=1,orderId=1
 Current consumption times: 12
ConsumeMessageThread_7 Receive New Messages: Hello RocketMQ i=2,orderId=2
 Current consumption times: 13
ConsumeMessageThread_8 Receive New Messages: Hello RocketMQ i=3,orderId=3
 Current consumption times: 14
ConsumeMessageThread_9 Receive New Messages: Hello RocketMQ i=4,orderId=4
 Current consumption times: 15
ConsumeMessageThread_10 Receive New Messages: Hello RocketMQ i=5,orderId=5
 Current consumption times: 16
ConsumeMessageThread_11 Receive New Messages: Hello RocketMQ i=6,orderId=6
 Current consumption times: 17
ConsumeMessageThread_12 Receive New Messages: Hello RocketMQ i=7,orderId=7
 Current consumption times: 18
ConsumeMessageThread_13 Receive New Messages: Hello RocketMQ i=8,orderId=8
 Current consumption times: 19
ConsumeMessageThread_14 Receive New Messages: Hello RocketMQ i=9,orderId=9
 Current consumption times: 20

Then, no matter how many times the order producer is started, the consumption order of the two consumers remains the same

Note: when a consumer is detected when a message is sent, the sent message will be sent directly to the subscribed consumer

3. Delete the topic, then close two consumers, and then start the order producer. After a few seconds, start two consumers
order producer:

orderId==>0,i=0
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34070000, offsetMsgId=C0A8016600002A9F0000000000018B36, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=0], queueOffset=0]
orderId==>1,i=1
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E343D0001, offsetMsgId=C0A8016600002A9F0000000000018C18, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=1], queueOffset=0]
orderId==>2,i=2
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E343F0002, offsetMsgId=C0A8016600002A9F0000000000018CFA, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=2], queueOffset=0]
orderId==>3,i=3
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34610003, offsetMsgId=C0A8016600002A9F0000000000018DDC, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=3], queueOffset=0]
orderId==>4,i=4
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34710004, offsetMsgId=C0A8016600002A9F0000000000018EBE, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=0], queueOffset=1]
orderId==>5,i=5
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34800005, offsetMsgId=C0A8016600002A9F0000000000018FA0, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=1], queueOffset=1]
orderId==>6,i=6
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E349F0006, offsetMsgId=C0A8016600002A9F0000000000019082, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=2], queueOffset=1]
orderId==>7,i=7
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E349F0007, offsetMsgId=C0A8016600002A9F0000000000019164, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=3], queueOffset=1]
orderId==>8,i=8
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34AF0008, offsetMsgId=C0A8016600002A9F0000000000019246, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=0], queueOffset=2]
orderId==>9,i=9
mqs Size of==>4
SendResult [sendStatus=SEND_OK, msgId=7F00000107DC73D16E939C8E34C00009, offsetMsgId=C0A8016600002A9F0000000000019328, messageQueue=MessageQueue [topic=TopicTestjjj, brokerName=localhost, queueId=1], queueOffset=2]

Ordinary consumers

Receive New Messages: Hello RocketMQ i=7,orderId=7
Receive New Messages: Hello RocketMQ i=1,orderId=1
Receive New Messages: Hello RocketMQ i=2,orderId=2
Receive New Messages: Hello RocketMQ i=5,orderId=5
Receive New Messages: Hello RocketMQ i=6,orderId=6
Receive New Messages: Hello RocketMQ i=3,orderId=3
Receive New Messages: Hello RocketMQ i=9,orderId=9
Receive New Messages: Hello RocketMQ i=0,orderId=0
Receive New Messages: Hello RocketMQ i=4,orderId=4
Receive New Messages: Hello RocketMQ i=8,orderId=8

It's basically completely chaotic and irregular

order consumer

ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=1,orderId=1
 Current consumption times: 1
ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=5,orderId=5
 Current consumption times: 2
ConsumeMessageThread_1 Receive New Messages: Hello RocketMQ i=9,orderId=9
 Current consumption times: 3
ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=0,orderId=0
 Current consumption times: 4
ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=4,orderId=4
 Current consumption times: 5
ConsumeMessageThread_2 Receive New Messages: Hello RocketMQ i=8,orderId=8
 Current consumption times: 6
ConsumeMessageThread_3 Receive New Messages: Hello RocketMQ i=3,orderId=3
 Current consumption times: 7
ConsumeMessageThread_3 Receive New Messages: Hello RocketMQ i=7,orderId=7
 Current consumption times: 8
ConsumeMessageThread_4 Receive New Messages: Hello RocketMQ i=2,orderId=2
 Current consumption times: 9
ConsumeMessageThread_4 Receive New Messages: Hello RocketMQ i=6,orderId=6
 Current consumption times: 10

It is observed that: first consume the information in queue 1, then consume the information in queue 0, queue 3 and queue 2, and realize the sequential consumption in local queues (messages are pushed one by one...)

4. Summary

  1. If the consumer is fixed and always exists, the message will be pushed to the consumer as soon as it is sent to the server
  2. Order consumers consume according to the message order of messageQueue (provided that all messages have been written to the queue)
  3. MessageQueueSelector is a queue selector that selects to publish the specified consumer queue. It can send messages to the specified queue. If there is only one queue, it can return a fixed queue
  4. context.setAutoCommit(false); Indicates that auto commit is turned off, which is equivalent to starting a transaction, and rollback can be performed
  5. ConsumeOrderlyStatus.SUCCESS; Indicates that the consumption is successful and the transaction is committed, ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT means that the queue currently sending messages to me will send messages to me after a specified period of time. ConsumeOrderlyStatus.COMMIT means that the message consumption is submitted manually. ConsumeOrderlyStatus.ROLLBACK means that the transaction is rolled back and the message is sent to me again

Posted by richever on Sat, 30 Oct 2021 18:39:52 -0700