RocketMQ(六)——Order Message(順序消息)


RocketMQ提供了3種模式的Producer:NormalProducer(普通)、OrderProducer(順序)、TransactionProducer(事務),對應的分別是普通消息、順序消息和事務消息。在前面的博客當中,涉及的都是NormalProducer,調用傳統的send方法,消息是無序的。接下來,看看順序消費。

模擬這樣一個場景,如果一個用戶完成一個訂單需要3條消息,比如訂單的創建、訂單的支付、訂單的發貨,很顯然,同一個用戶的訂單消息必須要順序消費,但是不同用戶之間的訂單可以並行消費。

生產者端

看一下生產者端的代碼:

DefaultMQProducer producer = new DefaultMQProducer("OrderProducer");
producer.setNamesrvAddr("192.168.99.9876");
producer.start();

String[] tags = new String[]{"createTag", "payTag", "sendTag"};

for (int orderId = 1; orderId <= 10; orderId++) {	//訂單消息
	for (int type = 0; type < 3; type++) {			//每種訂單分爲:創建訂單/支付訂單/發貨訂單
		Message msg = new Message("OrderTopic", 
				tag[type % tag.length], 
				orderId + ":" + type,
				(orderId + ":" + type).getBytes()
		);
		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();
				return mqs.get(index);
			}
		}, orderId);		
		System.out.println(sendResult);
	}
}
順序消費-producer

注意:一個Message除了Topic/Tag外,還有Key的概念。
上圖的send方法不同於以往,有一個MessageQueueSelector,將用於指定特定的消息發往特定的隊列當中!

消費者端

看一下消費者端的代碼:

consumer.registerMessageListener(new MessageListenerOrderly() {
	@Override
	public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
		try {		
			//模擬業務處理消息的時間
			Thread.sleep(new Random().nextInt(1000));
			System.out.println(new String(msgs.getBody(),"utf-8"));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ConsumeOrderlyStatus.SUCCESS;
	}
});
順序消費-consumer

注意:在以前普通消費消息時設置的回調是MessageListenerConcurrently,而順序消費的回調設置是MessageListenerOrderly。

運行效果

當我們啓動2個Consumer進行消費時,可以觀察到:
多個消費者消費的結果

多個消費者消費的結果

可以觀察得到,雖然從全局上來看,消息的消費不是有序的,但是每一個訂單下的3條消息是順序消費的!
其實,如果需要保證消息的順序消費,那麼很簡單,首先需要做到一組需要有序消費的消息發往同一個broker的同一個隊列上!其次消費者端採用有序Listener即可。

補充

這裏,RocketMQ底層是如何做到消息順序消費的,看一看源碼你就能大概瞭解到,至少來說,在多線程消費場景下,一個線程只去消費一個隊列上的消息,那麼自然就保證了消息消費的順序性,同時也保證了多個線程之間的併發性。也就是說其實broker並不能完全保證消息的順序消費,它僅僅能保證的消息的順序發送而已!
關於多線程消費這塊,RocketMQ早就替我們想好了,這樣設置即可:
消費多線程設置

消費多線程設置

想一想,在ActiveMQ中,我們如果想實現併發消費的話,恐怕還得搞個線程池提交任務吧,RocketMQ讓我們的工作變得簡單!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章