RocketMQ消息机制--重点笔记

一 顺序消息

应⽤场景
每⼀个订单有从下单、锁库存、⽀付、下物流等⼏个业务步骤。每个业务步骤都由⼀个消息⽣产者通知给下游服务。如何保证对每个订单的业务处理顺序不乱?
示例代码
⽣产者核⼼代码:
for (int i = 0; i < 10; i++) {
int orderId = i;
for(int j = 0 ; j <= 5 ; j ++){
Message msg =
new Message("OrderTopicTest", "order_"+orderId, "KEY" + orderId,
("order_"+orderId+" step " + j).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);
}
}, orderId);
System.out.printf("%s%n", sendResult);
}
}
通过MessageSelector,将orderId相同的消息,都转发到同⼀个MessageQueue中。
消费者核⼼代码:
consumer.registerMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
context.setAutoCommit(true);
for(MessageExt msg:msgs){
System.out.println("收到消息内容 "+new String(msg.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
注⼊⼀个MessageListenerOrderly实现
实现思路:
RocketMQ实现消息顺序消费,是需要⽣产者和消费者配合才能实现的。

image

 

1、⽣产者只有将⼀批有顺序要求的消息,放到同⼀个MesasgeQueue上,通过MessageQueue的FIFO特性保证这⼀批消息的顺序。
如果不指定MessageSelector对象,那么⽣产者会采⽤轮询的⽅式将多条消息依次发送到不同的MessageQueue上。
2、消费者需要实现MessageListenerOrderly接⼝,实际上在服务端,处理MessageListenerOrderly时,会给⼀个MessageQueue加锁,拿到
MessageQueue上所有的消息,然后再去读取下⼀个MessageQueue的消息。
注意点
1、理解局部有序与全局有序。⼤部分业务场景下,我们需要的其实是局部有序。如果要保持全局有序,那就只保留⼀个MessageQueue。性能
显然⾮常低。
2、⽣产者端尽可能将有序消息打散到不同的MessageQueue上,避免过于集中导致数据热点竞争。
3、消费者端只进⾏有限次数的重试。如果⼀条消息处理失败,RocketMQ会将后续消息阻塞住,让消费者进⾏重试。但是,如果消费者⼀直处
理失败,超过最⼤重试次数,那么RocketMQ就会跳过这⼀条消息,处理后⾯的消息,这会造成消息乱序。
4、消费者端如果确实处理逻辑中出现问题,不建议抛出异常,可以返回ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT
作为替代。
 
 

二 延迟消息 

应⽤场景
延迟消息发送是指消息发送到Apache RocketMQ后,并不期望⽴⻢投递这条消息,⽽是延迟⼀定时间后才投递到Consumer进⾏消费。 
核⼼⽅法
当前版本RocketMQ提供了两种实现延迟消息的机制,⼀种是指定固定的延迟级别,⼀种是指定消息发送时间
⽣产者端核⼼代码:
// 指定固定的延迟级别
Message message = new Message(TOPIC, ("Hello scheduled message " + i).getBytes(StandardCharsets.UTF_8));
message.setDelayTimeLevel(3); //10秒之后发送
// 指定消息发送时间
Message message = new Message(TOPIC, ("Hello scheduled message " + i).getBytes(StandardCharsets.UTF_8));
message.setDeliverTimeMs(System.currentTimeMillis() + 10_000L); //指定10秒之后的时间点
关于延迟级别,RocketMQ给消息定制了18个默认的延迟级别

image

 应⽤只需要根据⾃⼰的业务要求,选择对应的延迟级别即可。

实现思路
对于指定固定延迟级别的延迟消息,RocketMQ的实现⽅式是预设⼀个系统Topic,名字叫做SCHEDULE_TOPIC_XXXXX。在这个Topic下,预
设了18个MessageQueue。这⾥每个对列就对应了⼀种延迟级别。然后每次扫描这18个队列⾥的消息,进⾏延迟操作就可以了。 

image

 另外指定时间点的延迟消息,RocketMQ是通过时间轮算法实现的。 

 

三 批量消息

应⽤场景
⽣产者要发送的消息⽐较多时,可以将多条消息合并成⼀个批量消息,⼀次性发送出去。这样可以减少⽹络IO,提升消息发送的吞吐量。 
⽣产者核⼼代码:
List<Message> messages = new ArrayList<>(MESSAGE_COUNT);
for (int i = 0; i < MESSAGE_COUNT; i++) {
messages.add(new Message(TOPIC, TAG, "OrderID" + i, ("Hello world " +
i).getBytes(StandardCharsets.UTF_8)));
}
//split the large batch into small ones:
ListSplitter splitter = new ListSplitter(messages);
while (splitter.hasNext()) {
List<Message> listItem = splitter.next();
SendResult sendResult = producer.send(listItem);
System.out.printf("%s", sendResult);
}
注意点:
批量消息的使⽤⾮常简单,但是要注意RocketMQ做了限制。同⼀批消息的Topic必须相同,另外,不⽀持延迟消息。
还有批量消息的⼤⼩不要超过1M,如果太⼤就需要⾃⾏分割。

四 事务消息

具体见文档。

image

 

 

image

 

 
 
 
posted @ 2026-04-04 18:38  OMGq  阅读(4)  评论(0)    收藏  举报