系列文章目录
消息队列RocketMQ入门实践(一)
消息队列RocketMQ入门实践(二)
文章目录
前言
嗨,大家好,我是希留。
经过前面两篇文章的学习,相信大家对RocketMQ已经有了一个基本的了解了,这篇文章就来说一说RocketMQ的几个关键特性,废话不多说,咱开始吧。
一、顺序消息
在有的业务中,consumer在消费消息时,是需要按照生产者发送消息的顺序进行消费的,比如在电商系统中,订单的消息,会有创建订单、订单支付、订单完成,如果消息的顺序发生改变,那么这样的消息就没有意义了。
1.1 顺序消息的原理
要保证消息的顺序消费,有三个关键点:
- (1)消息顺序发送
- (2)消息顺序存储
- (3)消息顺序消费
第一点,消息顺序发送,多线程发送的消息无法保证有序性,因此,需要业务方在发送时,针对同一个业务编号(如同一笔订单)的消息需要保证在一个线程内顺序发送,在上一个消息发送成功后,在进行下一个消息的发送。对应到mq中,消息发送方法就得使用同步发送,异步发送无法保证顺序性
第二点,消息顺序存储,mq的topic下会存在多个queue,要保证消息的顺序存储,同一个业务编号的消息需要被发送到一个queue中。对应到mq中,需要使用MessageQueueSelector来选择要发送的queue,即对业务编号进行hash,然后根据队列数量对hash值取余,将消息发送到一个queue中
第三点,消息顺序消费,要保证消息顺序消费,同一个queue就只能被一个消费者所消费,因此对broker中消费队列加锁是无法避免的。同一时刻,一个消费队列只能被一个消费者消费,消费者内部,也只能有一个消费线程来消费该队列。即,同一时刻,一个消费队列只能被一个消费者中的一个线程消费
1.2 代码示例
生产者代码示例如下:
public class OrderProducer {
public static void main(String[] args) throws Exception{
DefaultMQProducer producer = new DefaultMQProducer("xiliu_producer_group");
producer.setNamesrvAddr("42.194.222.32:9876");
producer.start();
for (int i = 0; i<100; i++) {
String msgStr = "order -->" + i;
// 模拟生产订单id
int orderId = i % 10;
Message message = new Message("broker-a","order_msg",msgStr.getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(message,(mqs, msg, arg) -> {
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}<