RocketMQ角色詳解之Consumer

一、常用Consumer類

  • DefaultMQPushConsumer
  • DefaultMQPullConsumer

二者的區別:
DefaultMQPushConsumer:
系統控制讀取操作,收到消息後自動調用傳入的處理方法來處理,實時性高
DefaultMQPullConsumer:
讀取操作中的大部分功能由使用者自主控制 ,靈活性更高。

兩種Consumer的選取要主要取決於用戶的使用場景,適合的纔是最好的。

二、DefaultMQPushConsumer的使用

主要參數的設置:
  • ConsumerGroupName
  • NameServer地址及端口號
  • Topic

ConsumerGroupName

通過設置ConsumerGroupName將多個 Consumer組織到一起對同一topic進行消費, 提高併發處理能力,且ConsumerGroupName需與消息模式 (MessageModel)配合使用

MessageModel = Clustering時,
在 Clustering模式下,同一個 ConsumerGroup(GroupName相同) 裏的每個Consumer 只消費所訂閱消息的一部分內容, 同一個ConsumerGroup 裏所有的 Consumer消費的內容合起來纔是所訂閱 Topic 內容的整體, 從而達到負載均衡的目的 。

MessageModel = Broadcasting時,
同一個 ConsumerGroup裏的每個 Consumer都 能消費到所訂閱 Topic 的全部消息,也就是一個消息會被多次分發,被 多個 Consumer消費。

NameServer地址及端口號
可以填寫多個 ,用分號隔開,用以消除單點故障
如 “ip1:port;ip2:port;ip3 :port”

Topic
Topic名稱用來標識消息類型, 需要提前創建。
如果不需要消費某 個 Topic 下的所有消息,可以通過指定消息的 Tag 進行消息過濾,在填寫 Tag 參數的位置,若賦值爲 null 或 * 則表示要消費此Topic 的所有消息 。

參數設置完畢後將MessageListener註冊到該consumer即可自動監聽處理接收到的消息

詳細代碼如下:
package org.apache.rocketmq.example.simple;

import java.util.List;
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.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;

public class PushConsumer {

    public static void main(String[] args) throws InterruptedException, MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_JODIE_1");
        consumer.subscribe("Jodie_topic_1023", "*");
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.setConsumeTimestamp("20170422221800");
        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");
    }
}

DefaultMQPullConsumer的使用

DefaultMQPullConsumer對消息隊列的主要處理流程如下:

  1. 獲取Message Queue並遍歷
  2. 維護Offsetstore
  3. 根據不同消息狀態做不同的處理

具體代碼參考如下:

package org.apache.rocketmq.example.simple;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageQueue;

public class PullConsumer {
    private static final Map<MessageQueue, Long> OFFSE_TABLE = new HashMap<MessageQueue, Long>();

    public static void main(String[] args) throws MQClientException {
        DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("please_rename_unique_group_name_5");

        consumer.start();

        Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicTest1");
        for (MessageQueue mq : mqs) {
            System.out.printf("Consume from the queue: %s%n", mq);
            SINGLE_MQ:
            while (true) {
                try {
                    PullResult pullResult =
                        consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
                    System.out.printf("%s%n", pullResult);
                    putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
                    switch (pullResult.getPullStatus()) {
                        case FOUND:
                            break;
                        case NO_MATCHED_MSG:
                            break;
                        case NO_NEW_MSG:
                            break SINGLE_MQ;
                        case OFFSET_ILLEGAL:
                            break;
                        default:
                            break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        consumer.shutdown();
    }

    private static long getMessageQueueOffset(MessageQueue mq) {
        Long offset = OFFSE_TABLE.get(mq);
        if (offset != null)
            return offset;

        return 0;
    }

    private static void putMessageQueueOffset(MessageQueue mq, long offset) {
        OFFSE_TABLE.put(mq, offset);
    }

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