目录

1. SpringBoot集成RocketMQ组件

 2. RocketMQ发送不同类型的消息

3. 关于RocketMQ的介绍 

1、RocketMQ的作用

1.1、RocketMQ的流量削峰

 1.2、RocketMQ的异步解耦

2、RocketMQ的架构和基本概念

 3、RocketMQ的消息发送和接收

3.1、RocketMQ发送消息的步骤

 3.2、RocketMQ接收消息的步骤

4、RocketMQ发送的消息类型 

4.1 普通消息

4.2 顺序消息

4.3 事务消息 

4.3.1 事务消息的发送步骤

4.3.2 事务消息的回查步骤

5、消息消费的两种模式


MQ(Message Queue)是一种跨进程的通信机制,用于传递消息。使用MQ之后可以实现异步解耦和流量消峰的功能。在微服务项目中是一个常用的组件。RocketMQ的使用需要先启动RocketMQ的服务,这样才可以在后端连接RocketMQ并使用RocketMQ传递消息。

1. SpringBoot集成RocketMQ组件

首先我们需要在微服务的pom.xml文件中添加rocketmq的依赖

<!--rocketmq-->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.0.2</version>
</dependency>
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.4.0</version>
</dependency>

 然后我们在SpringBoot项目的application文件中配置RocketMQ的配置信息。

rocketmq:
    name-server: 192.168.109.131:9876 #rocketMQ服务的地址
    producer:
        group: shop-order # 生产者组

 我们配置好RocketMQ的信息之后,就可以在Controller控制层使用RocketMQ的功能了。

@RestController
@Slf4j
public class OrderController2 {
    @Autowired
    private OrderService orderService;
    @Autowired
    private ProductService productService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    //准备买1件商品
    @GetMapping("/order/prod/{pid}")
    public Order order(@PathVariable("pid") Integer pid) {
        log.info(">>客户下单,这时候要调用商品微服务查询商品信息");
        //通过fegin调用商品微服务
        Product product = productService.findByPid(pid);
        if (product == null){
            Order order = new Order();
            order.setPname("下单失败");
            return order;
        }
        log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));
        Order order = new Order();
        order.setUid(1);
        order.setUsername("测试用户");
        order.setPid(product.getPid());
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderService.save(order);
        //下单成功之后,将消息放到mq中
        rocketMQTemplate.convertAndSend("order-topic", order);
        return order;
    }
}

上述代码是消息的生产者微服务将消息发送到RocketMQ中,对于消息的消费者微服务也需要引入RocketMQ的依赖,然后对RocketMQ进行配置。最后在Controller读取RocketMQ中的消息。具体的代码示例如下所示,对于消息的接收,需要实现RocketMQListener<Order>类,类中的泛型Order是接收的消息类型。由控制台的日志我们也能看出,成功接收到了订单微服务发送的消息。

 2. RocketMQ发送不同类型的消息

RocketMQ可以发送可靠同步消息。可靠同步消息是指消息发送方发出消息后,会在收到接收方发挥响应之后才发送下一个数据包的通信方式。

//同步消息
@Test
public void testSyncSend() {
    //参数一: topic, 如果想添加tag 可以使用"topic:tag"的写法
    //参数二: 消息内容
    SendResult sendResult =rocketMQTemplate.syncSend("test-topic-1", "这是一条同步消息");
    System.out.println(sendResult);
}

RocketMQ可以发送可靠异步消息。可靠异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。发送方通过回调接口接收服务器响应,并对响应结果进行处理。异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知 启动转码服务,转码完成后通知推送转码结果等。具体的实例代码如下所示:

//异步发送是指发送方发出数据后,不等接收方发回邮件,接着发送下个数据包的通讯方式   发送方通过回调接口接收服务器响应,并对响应结果进行处理
    @Test
    public void testAsyncSend() throws InterruptedException{
        //该方法的第一个参数是topic  第二个参数是消息体 第三个参数是回调
        rocketMQTemplate.asyncSend("test-topic-1", "这是一条异步消息", new SendCallback() {

            //成功响应的回调
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }

            //异常响应的回调
            @Override
            public void onException(Throwable throwable) {
                System.out.println(throwable);
            }
        });
        System.out.println("==============================");
        //让进程休眠,确保回调函数能够执行
        Thread.sleep(300000000);
    }

RocketMQ可以发送单向消息。单向发送是指发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不 等待应答。 适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。单向消息的发送的示例代码如下所示:

    //单向消息
    @Test
    public void testOneWay(){
        rocketMQTemplate.sendOneWay("test-topic-1", "这是一条单向消息");
    }

3. 关于RocketMQ的介绍 

1、RocketMQ的作用

1.1、RocketMQ的流量削峰

在秒杀或团队抢购活动中,由于用户请求量较大,导致流量暴增,秒杀的应用在处理如此大量的访问流 量后,下游的通知系统无法承载海量的调用量,甚至会导致系统崩溃等问题而发生漏通知的情况。为解 决这些问题,可在应用和下游通知系统之间加入消息队列 MQ。直观图如下所示:

 1.2、RocketMQ的异步解耦

最常见的一个场景是用户注册后,需要发送注册邮件和短信通知,以告知用户注册成功。传统的做法如下:

此架构下注册、邮件、短信三个任务全部完成后,才返回注册结果到客户端,用户才能使用账号登录。 但是对于用户来说,注册功能实际只需要注册系统存储用户的账户信息后,该用户便可以登录,而后续 的注册短信和邮件不是即时需要关注的步骤。 所以实际当数据写入注册系统后,注册系统就可以把其他的操作放入对应的消息队列 MQ 中然后马上返 回用户结果,由消息队列 MQ 异步地进行这些操作。架构图如下:

异步解耦是消息队列 MQ 的主要特点,主要目的是减少请求响应时间和解耦。主要的使用场景就是将比 较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时,由于使用了消息队列 MQ,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦合。

2、RocketMQ的架构和基本概念

如上图所示,整体可以分成4个角色,分别是:NameServer,Broker,Producer,Consumer。 Broker(邮递员) Broker是RocketMQ的核心,负责消息的接收,存储,投递等功能

NameServer(邮局) 消息队列的协调者,Broker向它注册路由信息,同时Producer和Consumer向其获取路由信息。

Producer(寄件人) 消息的生产者,需要从NameServer获取Broker信息,然后与Broker建立连接,向Broker发送消息

Consumer(收件人) 消息的消费者,需要从NameServer获取Broker信息,然后与Broker建立连接,从Broker获取消息

Topic(地区) 用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息

Message Queue(邮件) 为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个 Message Queue读取消息

Message Message 是消息的载体。  

Producer Group 生产者组,简单来说就是多个发送同一类消息的生产者称之为一个生产者组。

Consumer Group 消费者组,消费同一类消息的多个 consumer 实例组成一个消费者组。

 3、RocketMQ的消息发送和接收

3.1、RocketMQ发送消息的步骤

1. 创建消息生产者, 指定生产者所属的组名 2. 指定Nameserver地址 3. 启动生产者 4. 创建消息对象,指定主题、标签和消息体 5. 发送消息 6. 关闭生产者。具体的代码如下所示:

//发送消息
public class RocketMQSendTest {
    public static void main(String[] args) throws Exception {
    //1. 创建消息生产者, 指定生产者所属的组名
    DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
    //2. 指定Nameserver地址
    producer.setNamesrvAddr("192.168.109.131:9876");
    //3. 启动生产者
    producer.start();
    //4. 创建消息对象,指定主题、标签和消息体
    Message msg = new Message("myTopic", "myTag",
                                ("RocketMQ Message").getBytes());
    //5. 发送消息
    SendResult sendResult = producer.send(msg,10000);
    System.out.println(sendResult);
    //6. 关闭生产者
    producer.shutdown();
    }
}

 3.2、RocketMQ接收消息的步骤

消息接收步骤: 1. 创建消息消费者, 指定消费者所属的组名 2. 指定Nameserver地址 3. 指定消费者订阅的主题和标签 4. 设置回调函数,编写处理消息的方法 5. 启动消息消费者。具体的消息接收代码如下所示:

//接收消息
public class RocketMQReceiveTest {
    public static void main(String[] args) throws MQClientException {
        //1. 创建消息消费者, 指定消费者所属的组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumergroup");
        //2. 指定Nameserver地址
        consumer.setNamesrvAddr("192.168.109.131:9876");
        //3. 指定消费者订阅的主题和标签
        consumer.subscribe("myTopic", "*");
        //4. 设置回调函数,编写处理消息的方法
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,ConsumeConcurrentlyContextcontext) {
                System.out.println("Receive New Messages: " + msgs);
                //返回消费状态
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //5. 启动消息消费者
        consumer.start();
        System.out.println("Consumer Started.");
    }
}

4、RocketMQ发送的消息类型 

4.1 普通消息

可靠同步发送。同步发送是指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。 此种方式应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等

可靠异步发送。异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。发送方通过回调接口接收服务器响应,并对响应结果进行处理。 异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知 启动转码服务,转码完成后通知推送转码结果等。

单向发送。单向发送是指发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不 等待应答。 适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

RocketMQ发送不同类型的消息的代码如下所示:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = OrderApplication.class)
public class MessageTypeTest {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    //下面是rocketmq的关于可靠同步消息的发送
    //同步发送是指消息发送发出消息后,会在收到接收方发回响应之后才发下一个数据包的通讯方式
    @Test
    public void testSyncSend(){
        //该方法的第一个参数是topic  第二个参数是消息体 第三个参数是超时时间
        //关于消息的tag的设计,允许topic:tag的方式设置消息的tag
        SendResult result = rocketMQTemplate.syncSend("test-topic-1:tag", "这是一条同步消息", 10000);
        System.out.println(result);
    }

    //异步发送是指发送方发出数据后,不等接收方发回邮件,接着发送下个数据包的通讯方式   发送方通过回调接口接收服务器响应,并对响应结果进行处理
    @Test
    public void testAsyncSend() throws InterruptedException{
        //该方法的第一个参数是topic  第二个参数是消息体 第三个参数是回调
        rocketMQTemplate.asyncSend("test-topic-1", "这是一条异步消息", new SendCallback() {

            //成功响应的回调
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println(sendResult);
            }

            //异常响应的回调
            @Override
            public void onException(Throwable throwable) {
                System.out.println(throwable);
            }
        });
        System.out.println("==============================");
        //让进程休眠,确保回调函数能够执行
        Thread.sleep(300000000);
    }

    //单向消息
    @Test
    public void testOneWay(){
        rocketMQTemplate.sendOneWay("test-topic-1", "这是一条单向消息");
    }

}

4.2 顺序消息

顺序消息是消息队列提供的一种严格按照顺序来发布和消费的消息类型。具体的图例如下所示:

 代码示例如下所示:

//同步顺序消息[异步顺序 单向顺序写法类似]
public void testSyncSendOrderly() {
    //第三个参数用于队列的选择
    rocketMQTemplate.syncSendOrderly("test-topic-1", "这是一条异步顺序消息","xxxx");
}

4.3 事务消息 

RocketMQ提供了事务消息,通过事务消息就能达到分布式事务的最终一致。事务消息的交互流程如下所示:

 半事务消息:暂不能投递的消息,发送方已经成功地将消息发送到了RocketMQ服务端,但是服务 端未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的 消息即半事务消息。

消息回查:由于网络闪断、生产者应用重启等原因,导致某条事务消息的二次确认丢失, RocketMQ服务端通过扫描发现某条消息长期处于“半事务消息”时,需要主动向消息生产者询问该 消息的最终状态(Commit 或是 Rollback),该询问过程即消息回查。

4.3.1 事务消息的发送步骤

1. 发送方将半事务消息发送至RocketMQ服务端。

2. RocketMQ服务端将消息持久化之后,向发送方返回Ack确认消息已经发送成功,此时消息为半事 务消息。

3. 发送方开始执行本地事务逻辑。

4. 发送方根据本地事务执行结果向服务端提交二次确认(Commit 或是 Rollback),服务端收到 Commit 状态则将半事务消息标记为可投递,订阅方最终将收到该消息;服务端收到 Rollback 状 态则删除半事务消息,订阅方将不会接受该消息。

4.3.2 事务消息的回查步骤

1. 在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达服务端,经过固定时 间后服务端将对该消息发起消息回查。

2. 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。

3. 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息 进行操作。

5、消息消费的两种模式

RocketMQ支持两种消息模式:

广播消费: 每个消费者实例都会收到消息,也就是一条消息可以被每个消费者实例处理;

集群消费: 一条消息只能被一个消费者实例消费

具体的代码示例如下所示:

@RocketMQMessageListener(
    consumerGroup = "shop",//消费者分组
    topic = "order-topic",//要消费的主题
    consumeMode = ConsumeMode.CONCURRENTLY, //消费模式:无序和有序
    messageModel = MessageModel.CLUSTERING, //消息模式:广播和集群,默认是集群
)
public class SmsService implements RocketMQListener<Order> {}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐