摘要
局部顺序消费:可以保证路由到同一个队列的消息是被顺序消费的。
全局顺序消费:让所有消息路由到同一个队列,这样就可以保证全局消费是顺序的。
这两种顺序,只是Producer指定队列的地方不一样,其它的都一样的。
示例
先看个简单的,全局顺序消费。同一个topic的所有消息是顺序消费的。
全局顺序消费
Producer
public class Producer {
public static void main(String[] args) throws UnsupportedEncodingException {
try {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("10.201.9.65:9876;10.201.9.67:9876");
producer.start();
String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
for (int i = 0; i < 10; i++) {
int orderId = i % 10;
Message msg =
new Message("TopicTest", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
/**
* 全局顺序、局部顺序差别就在这里。
* mqs 表示所有的队列
* msg 消息
* arg 传进来的参数的,根据这个参数选定队列。本示例传进来的就是固定的0队列。下个局部顺序示例,这里就是动态的参数i
*/
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, 0);
System.out.println("队列ID:"+ sendResult.getMessageQueue().getQueueId());
}
producer.shutdown();
} catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
e.printStackTrace();
}
}
}
Consumer
两个同样的Consumer示例(Consumer,Consumer2)
public class Consumer {
public static void main(String[] args) throws MQClientException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_3");
consumer.setNamesrvAddr("10.201.9.65:9876;10.201.9.67:9876");
/**
* 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br>
* 如果非第一次启动,那么按照上次消费的位置继续消费
*/
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
consumer.subscribe("TopicTest", "TagA || TagC || TagD");
consumer.registerMessageListener(new MessageListenerOrderly() {
AtomicLong consumeTimes = new AtomicLong(0);
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
this.consumeTimes.incrementAndGet();
context.setAutoCommit(true);
System.out.println("当前时间:"+System.currentTimeMillis()+"接收到消息,队列ID:"+context.getMessageQueue().getQueueId());
for(MessageExt msg:msgs){
System.out.println("消息内容为:"+new String(msg.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
结果分析
分析下面结果,消息都发送到同一个队列(0号队列,默认一般会有4条队列),所有消息都被Consumer给顺序消费了。
producer
消息内容:Hello RocketMQ 0
队列ID:0
消息内容:Hello RocketMQ 1
队列ID:0
消息内容:Hello RocketMQ 2
队列ID:0
消息内容:Hello RocketMQ 3
队列ID:0
消息内容:Hello RocketMQ 4
队列ID:0
消息内容:Hello RocketMQ 5
队列ID:0
消息内容:Hello RocketMQ 6
队列ID:0
消息内容:Hello RocketMQ 7
队列ID:0
消息内容:Hello RocketMQ 8
队列ID:0
消息内容:Hello RocketMQ 9
队列ID:0
Consumer
当前时间:1545659825114接收到消息,队列ID:0
消息内容为:Hello RocketMQ 0
当前时间:1545659825172接收到消息,队列ID:0
消息内容为:Hello RocketMQ 1
当前时间:1545659825232接收到消息,队列ID:0
消息内容为:Hello RocketMQ 2
当前时间:1545659825289接收到消息,队列ID:0
消息内容为:Hello RocketMQ 3
当前时间:1545659825344接收到消息,队列ID:0
消息内容为:Hello RocketMQ 4
当前时间:1545659825406接收到消息,队列ID:0
消息内容为:Hello RocketMQ 5
当前时间:1545659825473接收到消息,队列ID:0
消息内容为:Hello RocketMQ 6
当前时间:1545659825536接收到消息,队列ID:0
消息内容为:Hello RocketMQ 7
当前时间:1545659825604接收到消息,队列ID:0
消息内容为:Hello RocketMQ 8
当前时间:1545659825662接收到消息,队列ID:0
消息内容为:Hello RocketMQ 9
Consumer2
结果为空,没有任何消费
分区顺序消费
分区顺序消费,是在同一个队列里面的消息,按照顺序消费,但是在不同队列里面的消息,则不一定按顺序消费。
Producer
public class Producer {
public static void main(String[] args) throws UnsupportedEncodingException {
try {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("10.201.9.65:9876;10.201.9.67:9876");
producer.start();
String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
for (int i = 0; i < 10; i++) {
int orderId = i % 10;
Message msg =
new Message("TopicTest", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
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);
}
}, 0);
System.out.println("队列ID:"+ sendResult.getMessageQueue().getQueueId());
}
producer.shutdown();
} catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
e.printStackTrace();
}
}
}
Consumer
跟上面consumer代码一样
Consumer2
跟上面的Consumer代码一样
结果分析
producer 按照轮训的方式把消息发送到四个队列,consumer将消息安好队列归类,发现同一个队列里面的消息还是按照顺序消费的。
Producer结果
消息内容:Hello RocketMQ 0
队列ID:0
消息内容:Hello RocketMQ 1
队列ID:1
消息内容:Hello RocketMQ 2
队列ID:2
消息内容:Hello RocketMQ 3
队列ID:3
消息内容:Hello RocketMQ 4
队列ID:0
消息内容:Hello RocketMQ 5
队列ID:1
消息内容:Hello RocketMQ 6
队列ID:2
消息内容:Hello RocketMQ 7
队列ID:3
消息内容:Hello RocketMQ 8
队列ID:0
消息内容:Hello RocketMQ 9
队列ID:1
Consumer结果
当前时间:1545659891805接收到消息,队列ID:0
消息内容为:Hello RocketMQ 0
当前时间:1545659891866接收到消息,队列ID:1
消息内容为:Hello RocketMQ 1
当前时间:1545659891926接收到消息,队列ID:2
消息内容为:Hello RocketMQ 2
当前时间:1545659891984接收到消息,队列ID:3
消息内容为:Hello RocketMQ 3
当前时间:1545659892332接收到消息,队列ID:0
消息内容为:Hello RocketMQ 8
当前时间:1545659892392接收到消息,队列ID:1
消息内容为:Hello RocketMQ 9
Consumer2结果
当前时间:1545659892099接收到消息,队列ID:0
消息内容为:Hello RocketMQ 4
当前时间:1545659892159接收到消息,队列ID:1
消息内容为:Hello RocketMQ 5
当前时间:1545659892219接收到消息,队列ID:2
消息内容为:Hello RocketMQ 6
当前时间:1545659892290接收到消息,队列ID:3
消息内容为:Hello RocketMQ 7
Consumer 和 Consumer2 结果按照队列归类
队列0
Consumer
当前时间:1545659891805接收到消息,队列ID:0
消息内容为:Hello RocketMQ 0
Consumer2
当前时间:1545659892099接收到消息,队列ID:0
消息内容为:Hello RocketMQ 4
队列1
Consumer
当前时间:1545659891866接收到消息,队列ID:1
消息内容为:Hello RocketMQ 1
Consumer2
当前时间:1545659892159接收到消息,队列ID:1
消息内容为:Hello RocketMQ 5
Consumer
当前时间:1545659892392接收到消息,队列ID:1
消息内容为:Hello RocketMQ 9
队列2
Consumer
当前时间:1545659891926接收到消息,队列ID:2
消息内容为:Hello RocketMQ 2
Consumer2
当前时间:1545659892219接收到消息,队列ID:2
消息内容为:Hello RocketMQ 6
队列3
Consumer
当前时间:1545659891984接收到消息,队列ID:3
消息内容为:Hello RocketMQ 3
Consumer2
当前时间:1545659892290接收到消息,队列ID:3
消息内容为:Hello RocketMQ 7队列0
Consumer
当前时间:1545659891805接收到消息,队列ID:0
消息内容为:Hello RocketMQ 0
Consumer2
当前时间:1545659892099接收到消息,队列ID:0
消息内容为:Hello RocketMQ 4
队列1
Consumer
当前时间:1545659891866接收到消息,队列ID:1
消息内容为:Hello RocketMQ 1
Consumer2
当前时间:1545659892159接收到消息,队列ID:1
消息内容为:Hello RocketMQ 5
Consumer
当前时间:1545659892392接收到消息,队列ID:1
消息内容为:Hello RocketMQ 9
队列2
Consumer
当前时间:1545659891926接收到消息,队列ID:2
消息内容为:Hello RocketMQ 2
Consumer2
当前时间:1545659892219接收到消息,队列ID:2
消息内容为:Hello RocketMQ 6
队列3
Consumer
当前时间:1545659891984接收到消息,队列ID:3
消息内容为:Hello RocketMQ 3
Consumer2
当前时间:1545659892290接收到消息,队列ID:3
消息内容为:Hello RocketMQ 7