文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

二、RocketMQ 实战:顺序消息、事务消息与 SpringBoot 集成

1. 引言

在分布式系统中,消息中间件是解耦、削峰填谷、异步化的重要基础设施。阿里巴巴开源的 Apache RocketMQ,凭借其高性能、低延迟、高可用的特性,被广泛应用于金融、电商、物流等场景。

本文将从实战角度出发,深入探讨 顺序消息事务消息 的应用方式,并演示如何在 SpringBoot 中集成 RocketMQ,以便开发者快速落地生产级消息解决方案。


2. 顺序消息(Ordered Message)

2.1 背景

在某些业务场景下,消息的消费顺序至关重要。例如:

  • 电商订单流程:下单 → 支付 → 发货 → 收货。
  • 股票交易:挂单 → 撮合 → 成交 → 清算。

如果消息乱序消费,可能导致业务逻辑错误。

2.2 实现原理

RocketMQ 通过 队列分区 + 消费队列绑定 的方式保证顺序。

  • 生产者:根据业务 Key(如订单号)选择消息发送到同一个队列。
  • 消费者:一个队列只会被一个消费线程消费,从而保证同一 Key 的消息有序。

Mermaid 时序图:

ProducerMQBrokerConsumer发送消息(订单ID=1001, 创建订单)发送消息(订单ID=1001, 支付订单)发送消息(订单ID=1001, 发货订单)顺序投递消息先处理"创建订单"再处理"支付订单"最后处理"发货订单"ProducerMQBrokerConsumer

2.3 代码示例

// 顺序消息发送示例
SendResult result = producer.send(
    new Message("OrderTopic", "order", "1001", "创建订单".getBytes()),
    (mqs, msg, arg) -> {
        int queueIndex = Math.abs(arg.hashCode()) % mqs.size();
        return mqs.get(queueIndex);
    },
    "1001" // 订单号作为路由参数
);

3. 事务消息(Transactional Message)

3.1 背景

事务消息用于解决 分布式事务一致性 问题。例如:

  • 用户下单并支付,必须保证:

    • 扣款成功 → 订单状态更新成功。
    • 如果扣款失败 → 订单不能更新。

传统分布式事务(XA、2PC)效率低,RocketMQ 提供 事务消息机制 来实现最终一致性。

3.2 实现原理

事务消息采用 半消息 + 事务回查 的方式:

  1. 生产者发送半消息,Broker 暂存,不投递给消费者。

  2. 生产者执行本地事务(如扣款操作)。

  3. 根据事务结果提交:

    • Commit:消息正式投递给消费者。
    • Rollback:消息丢弃。
    • Unknown:Broker 会定期回查事务状态。

Mermaid 流程图:

成功
失败
不确定
发送半消息
执行本地事务
Commit 消息 -> 投递给消费者
Rollback 消息 -> 丢弃
Broker 定期回查事务状态

3.3 代码示例

// 事务消息发送示例
TransactionMQProducer producer = new TransactionMQProducer("tx-producer-group");
producer.setTransactionListener(new TransactionListener() {
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // 执行本地事务,例如扣款
        boolean success = doBusiness();
        return success ? LocalTransactionState.COMMIT_MESSAGE
                       : LocalTransactionState.ROLLBACK_MESSAGE;
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        // Broker 回查事务状态
        return LocalTransactionState.COMMIT_MESSAGE;
    }
});
producer.start();
producer.sendMessageInTransaction(new Message("TxTopic", "tag", "事务消息".getBytes()), null);

4. SpringBoot 集成 RocketMQ

4.1 引入依赖

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.3.0</version>
</dependency>

4.2 配置文件

rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    group: demo-producer-group

4.3 生产者示例

@Service
public class OrderProducer {
    @Resource
    private RocketMQTemplate rocketMQTemplate;

    public void sendOrderMessage(String orderId, String msg) {
        rocketMQTemplate.syncSendOrderly(
            "OrderTopic", 
            MessageBuilder.withPayload(msg).build(), 
            orderId // 使用订单号作为分区键
        );
    }
}

4.4 消费者示例

@RocketMQMessageListener(topic = "OrderTopic", consumerGroup = "order-consumer-group")
@Service
public class OrderConsumer implements RocketMQListener<String> {
    @Override
    public void onMessage(String message) {
        System.out.println("收到消息:" + message);
    }
}

5. 实践中的问题与优化

  1. 顺序消息并发度不足

    • 一个队列只能由一个线程消费,可能成为瓶颈。
    • 解决:根据业务 Key 合理分区,增加队列数。
  2. 事务消息回查频繁

    • 如果事务状态无法及时确认,Broker 会频繁回查。
    • 解决:优化本地事务逻辑,确保尽快返回结果。
  3. 消息堆积问题

    • 消费能力不足会导致堆积。
    • 解决:水平扩展消费者,提升并行度。

好的 ✅ 我来为你整理一个 可直接运行的 SpringBoot + RocketMQ Demo 工程源码,涵盖 顺序消息事务消息 的生产与消费示例。


6. RocketMQ SpringBoot Demo 工程结构

rocketmq-demo
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com.example.rocketmqdemo
│   │   │       ├── RocketmqDemoApplication.java  // 启动类
│   │   │       ├── producer
│   │   │       │   ├── OrderProducer.java        // 顺序消息生产者
│   │   │       │   └── TxProducer.java           // 事务消息生产者
│   │   │       └── consumer
│   │   │           ├── OrderConsumer.java        // 顺序消息消费者
│   │   │           └── TxConsumer.java           // 事务消息消费者
│   │   └── resources
│   │       └── application.yml                   // 配置文件

1. Maven 依赖(pom.xml)

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>rocketmq-demo</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
    </parent>

    <dependencies>
        <!-- SpringBoot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- RocketMQ SpringBoot Starter -->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>

        <!-- Lombok (可选) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. 配置文件(application.yml)

spring:
  application:
    name: rocketmq-demo

rocketmq:
  name-server: 127.0.0.1:9876
  producer:
    group: demo-producer-group

3. 启动类

package com.example.rocketmqdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RocketmqDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RocketmqDemoApplication.class, args);
    }
}

4. 顺序消息

4.1 生产者(OrderProducer.java)
package com.example.rocketmqdemo.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

@Service
public class OrderProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendOrderMessage(String orderId, String msg) {
        rocketMQTemplate.syncSendOrderly(
                "OrderTopic",
                MessageBuilder.withPayload(msg).build(),
                orderId // 按订单号分区
        );
        System.out.println("发送顺序消息: " + msg);
    }
}
4.2 消费者(OrderConsumer.java)
package com.example.rocketmqdemo.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;

@Service
@RocketMQMessageListener(topic = "OrderTopic", consumerGroup = "order-consumer-group")
public class OrderConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("消费顺序消息: " + message);
    }
}

5. 事务消息

5.1 生产者(TxProducer.java)
package com.example.rocketmqdemo.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

@Service
public class TxProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public void sendTransactionMessage(String content) {
        Message<String> msg = MessageBuilder.withPayload(content).build();
        rocketMQTemplate.sendMessageInTransaction("TxTopic", msg, null);
        System.out.println("发送事务消息: " + content);
    }
}
5.2 本地事务监听器(TxListener.java)
package com.example.rocketmqdemo.producer;

import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.messaging.Message;

@RocketMQTransactionListener(txProducerGroup = "demo-producer-group")
public class TxListener implements RocketMQLocalTransactionListener {

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        System.out.println("执行本地事务: " + msg.getPayload());
        // 模拟业务逻辑
        boolean success = true;
        return success ? RocketMQLocalTransactionState.COMMIT
                       : RocketMQLocalTransactionState.ROLLBACK;
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        System.out.println("回查事务消息: " + msg.getPayload());
        return RocketMQLocalTransactionState.COMMIT;
    }
}
5.3 消费者(TxConsumer.java)
package com.example.rocketmqdemo.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;

@Service
@RocketMQMessageListener(topic = "TxTopic", consumerGroup = "tx-consumer-group")
public class TxConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        System.out.println("消费事务消息: " + message);
    }
}

7. 测试

可以在 RocketmqDemoApplication 启动后,写一个简单的 CommandLineRunner 测试:

@Bean
CommandLineRunner test(OrderProducer orderProducer, TxProducer txProducer) {
    return args -> {
        // 发送顺序消息
        orderProducer.sendOrderMessage("1001", "订单创建");
        orderProducer.sendOrderMessage("1001", "订单支付");
        orderProducer.sendOrderMessage("1001", "订单发货");

        // 发送事务消息
        txProducer.sendTransactionMessage("事务消息: 用户下单并扣款");
    };
}

运行后,你会看到控制台输出:

发送顺序消息: 订单创建
消费顺序消息: 订单创建
发送顺序消息: 订单支付
消费顺序消息: 订单支付
发送事务消息: 事务消息: 用户下单并扣款
执行本地事务: 事务消息: 用户下单并扣款
消费事务消息: 事务消息: 用户下单并扣款

8. 总结

本文介绍了 RocketMQ 中两大核心特性:

  • 顺序消息:保障业务消息严格顺序。
  • 事务消息:解决分布式事务一致性问题。

并演示了如何通过 SpringBoot 集成 RocketMQ,从而快速构建生产级的消息驱动应用。

在实践中,还需关注 消息可靠性、消费并发度、事务回查优化 等问题,以保证系统的稳定性与高可用性。

posted @ 2025-09-17 16:23  NeoLshu  阅读(16)  评论(0)    收藏  举报  来源