RocketMQ系列---消息消費者及消費方式

1.消息消費

public class Consumer {

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

    	// 實例化消費者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");

    	// 設置NameServer的地址
        consumer.setNamesrvAddr("localhost:9876");

    	// 訂閱一個或者多個Topic,以及Tag來過濾需要消費的消息
        consumer.subscribe("TopicTest", "*");
    	// 註冊回調實現類來處理從broker拉取回來的消息
        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);
                // 標記該消息已經被成功消費
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 啓動消費者實例
        consumer.start();
        System.out.printf("Consumer Started.%n");
	}
}

2.順序消費

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;

package org.apache.rocketmq.example.order2;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
* 順序消息消費,帶事務方式(應用可控制Offset什麼時候提交)
*/
public class ConsumerInOrder {

   public static void main(String[] args) throws Exception {
       DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_3");
       consumer.setNamesrvAddr("127.0.0.1:9876");
       /**
        * 設置Consumer第一次啓動是從隊列頭部開始消費還是隊列尾部開始消費<br>
        * 如果非第一次啓動,那麼按照上次消費的位置繼續消費
        */
       consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

       consumer.subscribe("TopicTest", "TagA || TagC || TagD");

       consumer.registerMessageListener(new MessageListenerOrderly() {

           Random random = new Random();

           @Override
           public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
               context.setAutoCommit(true);
               for (MessageExt msg : msgs) {
                   // 可以看到每個queue有唯一的consume線程來消費, 訂單對每個queue(分區)有序
                   System.out.println("consumeThread=" + Thread.currentThread().getName() + "queueId=" + msg.getQueueId() + ", content:" + new String(msg.getBody()));
               }

               try {
                   //模擬業務邏輯處理中...
                   TimeUnit.SECONDS.sleep(random.nextInt(10));
               } catch (Exception e) {
                   e.printStackTrace();
               }
               return ConsumeOrderlyStatus.SUCCESS;
           }
       });

       consumer.start();

       System.out.println("Consumer Started.");
   }
}

3.PushConsumer,PullConsumer消費模式分析

Push:實時性高,但是增加服務器負載,消費能力不同,如果push過快,消費端會出現很多問題;

Pull:消費者從Server端拉取資源,主動權在消費端,可控性好,但是間隔時間不好控制,間隔時間太短,則空請求,資源浪費,間隔時間太長,則消息不能及時處理;

長輪詢:Client請求Server服務端(Broker),Broker會保持一段時間的連接,默認是15s,如果這段時間沒有消息達到,則離開返回給Customer,沒有消息的話,超過15s,則返回空,再進行重新請求,缺點:服務端需要保持Customer的請求,會佔用資源,需要客戶端連接數可控,否則會一段連接。

PushConsumer:本質是長輪詢;

1.系統收到消息後自動處理消息和offset,如果有新的Consumer加入會自動做負載均衡,

2.在broker端可以通過longPolling=true來開啓長輪詢,

3.消費端代碼:DefaultMQPushConsumerImpl->pullMessage->PullCallback

4.服務端代碼:broker.longpolling

5.雖然是push,但代碼裏面大量使用了pull,是因爲使用了長輪詢方式達到push效果,既有pull有的,又有push的實現性。

6.關閉優雅:只要是釋放資源和保存offset,調用shutdown()即可,參考@PostConstruct,@PreDestory。

PullConsumer:需要自己維護offset;

1.獲取MessageQueue遍歷;

2.客戶維護offset,需要本地用戶存儲offset,存儲內存,磁盤數據庫等;

3.處理不同狀態的消息FOUND,NO_NEW_MSG,OFFSET_ILLRGL,NO_MATCHED_MSG,4種狀態;

4.靈活性強,但編碼複雜度高;

5.關閉優雅,注意是釋放資源和保存offset,需要程序自己保存offset,特別是異常處理的時候;

 

 

 

 

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