一、问题思考
消息拉取在实践过程中,有以下几个问题需要考虑:
1、如何全量拉取消息?
2、如何指定MessageQueue从指定offset处拉取消息?
3、如何更新MessageQueue的Offset标志位?
4、Pull模式下如何实现负载均衡?
二、Pull模式下常用Demo
1、更新MessageQueue的Offset标志位
consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset());
2、Pull模式简单Demo
public static void main(String[] args) throws MQClientException {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("PullConsumer");
consumer.setNamesrvAddr("10.72.86.241:9876;10.72.86.229:9876");
consumer.start();
// 从指定topic中拉取所有消息队列
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("user-info");
for (MessageQueue mq : mqs) {
// 获取消息的offset,指定从store中获取
long offset = consumer.fetchConsumeOffset(mq, true);
System.out.println("consumer from the queue:" + mq + ":" + offset);
try {
while (true) {
PullResult pullResult = consumer.pullBlockIfNotFound(mq,
null, consumer.fetchConsumeOffset(mq, false), 1);
consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset());
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageExt> messageExtList = pullResult.getMsgFoundList();
for (MessageExt m : messageExtList) {
System.out.println(m.toString());
}
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break;
case OFFSET_ILLEGAL:
break;
default:
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
consumer.shutdown();
}
3、指定MessageQueue拉取消息
public class PullMQConsumerMain {
public static void main(String[] args) throws MQClientException {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("PullConsumer");
consumer.setNamesrvAddr("10.72.86.241:9876;10.72.86.229:9876");
consumer.start();
try {
//从指定topic的MessageQueue中拉取消息
MessageQueue mq = new MessageQueue();
mq.setQueueId(0);
mq.setTopic("user-info");
mq.setBrokerName("broker-a");
//指定获取消息的offset
long offset = 26;
PullResult pullResult = consumer.pullBlockIfNotFound(mq, null, offset, 32);
//更新offset
consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset());
System.out.println("最新 offset :" + consumer.fetchConsumeOffset(mq, false));
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageExt> messageExtList = pullResult
.getMsgFoundList();
for (MessageExt m : messageExtList) {
System.out.println(m.toString());
}
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break;
case OFFSET_ILLEGAL:
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
consumer.shutdown();
}
}
4、Pull模式下负载均衡(MQPullConsumerScheduleService)
public class PullScheduleMain {
public static void main(String[] args) throws MQClientException {
final MQPullConsumerScheduleService scheduleService = new MQPullConsumerScheduleService("PullSchedule");
scheduleService.getDefaultMQPullConsumer().setNamesrvAddr("10.72.86.241:9876;10.72.86.229:9876");
scheduleService.setMessageModel(MessageModel.CLUSTERING);
scheduleService.registerPullTaskCallback("user-info", new PullTaskCallback() {
@Override
public void doPullTask(MessageQueue mq, PullTaskContext context) {
// TODO Auto-generated method stub
MQPullConsumer consumer = context.getPullConsumer();
try {
long offset = consumer.fetchConsumeOffset(mq, false);
if(offset < 0)
offset = 0;
PullResult pullResult = consumer.pullBlockIfNotFound(mq, null, offset, 4);
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageExt> messageExtList = pullResult
.getMsgFoundList();
for (MessageExt m : messageExtList) {
System.out.println(m.toString());
}
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break;
case OFFSET_ILLEGAL:
break;
default:
break;
}
consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset());
context.setPullNextDelayTimeMillis(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
});
scheduleService.start();
}
}
三、总结
分别用四个例子回答了上面的4个问题,后续会通过源码解析的方式描述Pull模式的实现机制。
遗留问题:
调用fetchMessageQueuesInBalance函数时,返回MessageQueue为空