消息有序指的是可以按照消息的发送顺序消费(FIFO)。RocketMQ可以严格保证消息有序性,可以分为分区有序或者全局有序。
消费顺序原理:
在默认情况下消息发送采用round robin轮询方式把消息发送到不同的queue,而消费消息时从多个queue上获取消息,这种情况无法保证有序性,但是如果消息只发送到同一个queue中,消费时只从该queue中拉取,就可保证有序。当发送和消费只有一个queue,则全局有序,如果多个queue参与,则为分区有序,即相对每个queue消息都是有序的
下面用订单进行分区有序的实例,一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被推送到一个queue中,按序被消费
先创建一个订单集合
public class OrderStep {
private Long orderId;
private String desc;
public OrderStep(){}
public OrderStep(Long orderId, String desc) {
this.orderId = orderId;
this.desc = desc;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "OrderStep{" +
"orderId=" + orderId +
", desc='" + desc + '\'' +
'}';
}
public static List<OrderStep> buildOrders(){
List<OrderStep> orderSteps = new ArrayList<>();
orderSteps.add(new OrderStep(00001L,"创建"));
orderSteps.add(new OrderStep(00001L,"付款"));
orderSteps.add(new OrderStep(00001L,"消费"));
orderSteps.add(new OrderStep(00001L,"完成"));
orderSteps.add(new OrderStep(00002L,"创建"));
orderSteps.add(new OrderStep(00002L,"付款"));
orderSteps.add(new OrderStep(00002L,"消费"));
orderSteps.add(new OrderStep(00002L,"完成"));
orderSteps.add(new OrderStep(00003L,"创建"));
orderSteps.add(new OrderStep(00003L,"付款"));
orderSteps.add(new OrderStep(00003L,"消费"));
orderSteps.add(new OrderStep(00003L,"完成"));
orderSteps.add(new OrderStep(00004L,"创建"));
orderSteps.add(new OrderStep(00004L,"付款"));
orderSteps.add(new OrderStep(00004L,"消费"));
orderSteps.add(new OrderStep(00004L,"完成"));
return orderSteps;
}
}
消息发送者
public class SyncOrderStepProducer {
public static void main(String[] args) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
// 1.创建消息生产者,并且制定生产者组名
DefaultMQProducer producer = new DefaultMQProducer("group1");
// 设置超时时间
producer.setSendMsgTimeout(10000);
// 2.指定namesrv地址
producer.setNamesrvAddr("192.168.48.128:9876;192.168.48.137:9876");
// producer.setNamesrvAddr("47.96.165.93:9876;106.52.131.197:9876");
// 3.启动producer
try {
producer.start();
} catch (
MQClientException e) {
e.printStackTrace();
}
List<OrderStep> orderStepList = OrderStep.buildOrders();
for (OrderStep order: orderStepList){
// 4.创建消息对象,指定主题topic,tag和消息体
Message msg = new Message("orderTopic","order","order"+order.getOrderId(),order.getDesc().getBytes());
// 5.发送消息,参数1:消息对象;参数2:消息队列的选择器;参数3:选择队列的业务标识(orderId)
SendResult result = producer.send(msg, new MessageQueueSelector() {
/**
*
* @param list 消息队列集合
* @param message 消息对象
* @param o 业务标识
* @return
*/
@Override
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
long orderId = (long) o;
int index = (int) (orderId%list.size());
return list.get(index);
}
},order.getOrderId());
SendStatus status = result.getSendStatus();
String msgId = result.getMsgId();
int queueId = result.getMessageQueue().getQueueId();
System.out.println("send status:"+status+",message ID:"+msgId+",queue:"+queueId+",desc:"+order.getDesc());
}
// * 关闭producer
producer.shutdown();
}
}
消息消费者
public class OrderStepConsumer {
public static void main(String[] args) {
consumer();
}
public static void consumer(){
// 1 创建消费者Consumer ,并确定消费者组名
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");
// 2 指定NameServer地址
consumer.setNamesrvAddr("192.168.48.128:9876;192.168.48.137:9876");
// consumer.setNamesrvAddr("106.52.131.197:9876;47.96.165.93:9876");
try {
// 3 订阅主题Topic和Tag
consumer.subscribe("orderTopic","*");
// 4 设置回调函数,处理消息
consumer.registerMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
for(MessageExt msg:list){
System.out.println(Thread.currentThread().getName()+",消费消息:"+new String(msg.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
// 5 启动消息内容
consumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
}
启动消费者和发送者
发送成功
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B610000,queue:1,desc:创建
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B710001,queue:1,desc:付款
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B730002,queue:1,desc:消费
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B750003,queue:1,desc:完成
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B790004,queue:2,desc:创建
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B7A0005,queue:2,desc:付款
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B860006,queue:2,desc:消费
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B910007,queue:2,desc:完成
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B950008,queue:3,desc:创建
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B970009,queue:3,desc:付款
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B9D000A,queue:3,desc:消费
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47B9E000B,queue:3,desc:完成
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47BA0000C,queue:0,desc:创建
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47BA9000D,queue:0,desc:付款
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47BAC000E,queue:0,desc:消费
send status:SEND_OK,message ID:C0A800033A0C18B4AAC251E47BAF000F,queue:0,desc:完成
接收成功,消费者开了四个线程,一个线程监听一个队列
ConsumeMessageThread_3,消费消息:创建
ConsumeMessageThread_4,消费消息:创建
ConsumeMessageThread_1,消费消息:创建
ConsumeMessageThread_2,消费消息:创建
ConsumeMessageThread_4,消费消息:付款
ConsumeMessageThread_3,消费消息:付款
ConsumeMessageThread_4,消费消息:消费
ConsumeMessageThread_2,消费消息:付款
ConsumeMessageThread_4,消费消息:完成
ConsumeMessageThread_1,消费消息:付款
ConsumeMessageThread_2,消费消息:消费
ConsumeMessageThread_3,消费消息:消费
ConsumeMessageThread_1,消费消息:消费
ConsumeMessageThread_2,消费消息:完成
ConsumeMessageThread_1,消费消息:完成
ConsumeMessageThread_3,消费消息:完成