RocketMQ 使用指南

0 阅读13分钟

概述

公司项目完成 RocketMQ 5.x 的集成和封装,提供了类型安全、易于使用的消息队列组件。

核心组件

order-justgotrip-business/
└── com.justgotrip.hotel.booking.mq/
    ├── message/
    │   ├── RocketMQMessage.java        # 通用消息实体(泛型)
    │   └── DelayLevel.java             # 延迟级别枚举(18级)
    ├── sender/
    │   ├── RocketMQSender.java         # 消息发送器封装
    │   ├── RocketMQDelaySender.java    # 延迟消息发送器
    │   └── RocketMQTransactionSender.java # 事务消息发送器
    ├── consumer/
    │   └── RocketMQConsumer.java       # 消费者工具类
    ├── OrderMessageProducer.java       # 订单消息生产者示例
    └── OrderMessageListener.java       # 订单消息消费者示例

特性

  • 泛型支持: 类型安全的消息体
  • 批量消息: 支持批量发送提升吞吐量
  • 延迟消息: 18个延迟级别(1秒~2小时),支持自动计算
  • 事务消息: 分布式事务一致性保证
  • 顺序消息: 保证消息顺序消费
  • 异步发送: 提升发送性能
  • 消息追踪: 自动生成任务ID
  • 扩展信息: 支持自定义元数据

快速开始

1. 配置文件

application.yml

rocketmq:
  # NameServer 地址
  name-server: 127.0.0.1:9876
  # 生产者配置
  producer:
    group: hotel-booking-producer
    send-message-timeout: 3000
    max-message-size: 4194304
    compress-message-body-threshold: 4096
  # 消费者配置
  consumer:
    # Job模块消费者组
    group: hotel-booking-job-consumer
    # Business模块消费者组
    business-group: hotel-booking-business-consumer
    message-model: CLUSTERING
    consume-thread-min: 20
    consume-thread-max: 64
    consume-message-batch-max-size: 1

2. 添加依赖(已完成)

order-justgotrip-business/pom.xml

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client-java</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>

3. Hello World

发送消息

@Service
public class OrderService {

    private final RocketMQSender rocketMQSender;

    public void sendOrderMessage() {
        // 构建消息
        RocketMQMessage<OrderDTO> message = RocketMQSender.buildMessage(
            "hotel-order-topic",    // topic
            "order_create",         // tag
            orderDTO                // body
        );

        // 同步发送
        SendResult result = rocketMQSender.send(message);
        System.out.println("消息发送成功: " + result.getMsgId());
    }
}

消费消息

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    consumerGroup = "hotel-booking-business-consumer"
)
public class OrderMessageListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("收到消息: {}", message);
        // 处理业务逻辑
    }
}

消息实体详解

RocketMQMessage 核心属性

public class RocketMQMessage<T> implements Serializable {
    private String topic;                  // 主题(必填)
    private String tag;                    // 标签(可选,用于过滤)
    private String key;                    // 消息Key(可选,用于幂等和查询)
    private DelayLevel delayLevel;         // 延迟级别
    private T message;                     // 单条消息体
    private List<T> messages;              // 批量消息体
    private String hashKey;                // 有序消息的HashKey
    private String taskId;                 // 任务ID(自动生成)
    private Map<String, Object> ext;       // 扩展信息
}

延迟级别枚举

级别延迟时间使用场景
OFF不延迟默认
LEVEL_11秒短暂延迟
LEVEL_25秒重试延迟
LEVEL_310秒补偿延迟
LEVEL_430秒订单超时检查
LEVEL_51分钟支付超时
LEVEL_62分钟状态同步延迟
LEVEL_95分钟定时任务
LEVEL_1410分钟长延迟任务
LEVEL_1630分钟半小时延迟
LEVEL_171小时一小时延迟
LEVEL_182小时两小时延迟

Builder 模式构建消息

RocketMQMessage<OrderDTO> message = RocketMQMessage.<OrderDTO>builder()
    .topic("hotel-order-topic")           // 必填
    .tag("order_status")                   // 可选
    .key(orderId.toString())               // 可选,用于幂等
    .message(orderDTO)                     // 单条消息
    .delayLevel(DelayLevel.LEVEL_5)        // 延迟1分钟
    .taskId("custom-task-id")              // 可选,不填则自动生成
    .putExt("traceId", traceId)            // 扩展信息
    .putExt("source", "API")               // 扩展信息
    .build();

消息发送

1. 同步发送

适用场景: 重要消息,需要确认发送成功

@Service
public class OrderService {

    private final RocketMQSender rocketMQSender;

    public void createOrder(OrderDTO orderDTO) {
        // 构建消息
        RocketMQMessage<OrderDTO> message = RocketMQSender.buildMessage(
            "hotel-order-topic",
            "order_create",
            orderDTO
        );

        // 同步发送
        SendResult result = rocketMQSender.send(message);
        log.info("订单创建消息发送成功, msgId: {}, orderId: {}",
            result.getMsgId(), orderDTO.getOrderId());
    }
}

2. 异步发送

适用场景: 高并发场景,不阻塞主线程

@Service
public class OrderService {

    private final RocketMQSender rocketMQSender;

    public void updateOrderStatusAsync(Long orderId, String status) {
        Map<String, Object> body = new HashMap<>();
        body.put("orderId", orderId);
        body.put("status", status);
        body.put("timestamp", System.currentTimeMillis());

        RocketMQMessage<Map<String, Object>> message =
            RocketMQSender.buildMessage("hotel-order-topic", "order_status", body);

        // 异步发送
        rocketMQSender.sendAsync(message, new SendCallback() {
            @Override
            public void onSuccess(SendResult result) {
                log.info("订单状态消息发送成功 - orderId:{}, msgId:{}",
                    orderId, result.getMsgId());
            }

            @Override
            public void onException(Throwable e) {
                log.error("订单状态消息发送失败 - orderId:{}", orderId, e);
                // 可以在这里加入重试逻辑
            }
        });
    }
}

3. 批量发送

适用场景: 需要发送大量消息,提升吞吐量

@Service
public class BatchOrderService {

    private final RocketMQSender rocketMQSender;

    public void batchCreateOrders(List<OrderDTO> orders) {
        // 构建批量消息
        RocketMQMessage<OrderDTO> message = RocketMQSender.buildBatchMessage(
            "hotel-order-topic",
            "order_batch",
            orders
        );

        // 批量发送
        SendResult result = rocketMQSender.sendBatch(message);
        log.info("批量订单消息发送成功, count:{}, msgId:{}",
            orders.size(), result.getMsgId());
    }
}

4. 延迟消息

适用场景: 定时任务、超时检查、延迟处理

@Service
public class PaymentTimeoutService {

    private final RocketMQSender rocketMQSender;

    public void createOrderWithPaymentCheck(OrderDTO orderDTO) {
        // 1. 发送订单创建消息(立即)
        RocketMQMessage<OrderDTO> createMsg = RocketMQSender.buildMessage(
            "hotel-order-topic",
            "order_create",
            orderDTO
        );
        rocketMQSender.send(createMsg);

        // 2. 发送支付超时检查消息(延迟30分钟)
        Map<String, Object> timeoutBody = new HashMap<>();
        timeoutBody.put("orderId", orderDTO.getOrderId());
        timeoutBody.put("checkType", "PAYMENT_TIMEOUT");

        RocketMQMessage<Map<String, Object>> timeoutMsg =
            RocketMQSender.buildDelayMessage(
                "hotel-order-topic",
                "order_timeout",
                timeoutBody,
                DelayLevel.LEVEL_16  // 30分钟
            );
        rocketMQSender.sendDelay(timeoutMsg, DelayLevel.LEVEL_16);
    }
}

5. 顺序消息

适用场景: 需要保证消息顺序(同一订单的消息按顺序消费)

@Service
public class OrderStatusService {

    private final RocketMQSender rocketMQSender;

    public void updateOrderStatus(Long orderId, String status) {
        Map<String, Object> body = new HashMap<>();
        body.put("orderId", orderId);
        body.put("status", status);
        body.put("timestamp", System.currentTimeMillis());

        // 使用 orderId 作为 hashKey,保证同一订单的消息进入同一队列
        RocketMQMessage<Map<String, Object>> message =
            RocketMQSender.buildOrderlyMessage(
                "hotel-order-topic",
                "order_status",
                body,
                orderId.toString()  // hashKey
            );

        rocketMQSender.sendOrderly(message);
    }
}

6. 单向发送

适用场景: 不关心发送结果,追求最高性能

@Service
public class LogService {

    private final RocketMQSender rocketMQSender;

    public void sendLog(LogEntry log) {
        RocketMQMessage<LogEntry> message = RocketMQSender.buildMessage(
            "log-topic",
            "operation_log",
            log
        );

        // 单向发送,不等待响应
        rocketMQSender.sendOneWay(message);
    }
}

消息消费

1. 基础消费者

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    consumerGroup = "hotel-booking-business-consumer"
)
public class OrderMessageListener implements RocketMQListener<String> {

    private static final Logger log = LoggerFactory.getLogger(OrderMessageListener.class);

    @Override
    public void onMessage(String message) {
        log.info("收到订单消息: {}", message);

        // 解析消息
        Map<String, Object> msgMap = JSON.parseObject(message, Map.class);
        Long orderId = (Long) msgMap.get("orderId");
        String status = (String) msgMap.get("status");

        // 处理业务逻辑
        handleOrderStatusChange(orderId, status);
    }

    private void handleOrderStatusChange(Long orderId, String status) {
        // 业务处理逻辑
    }
}

2. 使用消费者工具类

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    consumerGroup = "hotel-booking-business-consumer"
)
public class EnhancedOrderListener implements RocketMQListener<String> {

    private static final Logger log = LoggerFactory.getLogger(EnhancedOrderListener.class);

    @Override
    public void onMessage(String message) {
        // 创建消费者上下文
        RocketMQConsumer.ConsumerContext context = RocketMQConsumer.createContext(
            "hotel-order-topic",
            null,  // tag
            "hotel-booking-business-consumer"
        );

        // 记录接收日志
        RocketMQConsumer.logReceived(message, context);

        long startTime = System.currentTimeMillis();
        try {
            // 解析并处理消息
            processMessage(message);

            // 记录成功日志
            RocketMQConsumer.logSuccess(message, System.currentTimeMillis() - startTime);
        } catch (Exception e) {
            // 记录错误日志
            RocketMQConsumer.logError(message, e);
            throw e;
        }
    }

    private void processMessage(String message) {
        // 业务处理逻辑
    }
}

3. 按Tag过滤消费

// 消费者1:只处理订单创建消息
@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    selectorExpression = "order_create",
    consumerGroup = "order-create-consumer"
)
public class OrderCreateListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("处理订单创建: {}", message);
        // 只处理 order_create tag 的消息
    }
}

// 消费者2:只处理订单状态变更消息
@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    selectorExpression = "order_status",
    consumerGroup = "order-status-consumer"
)
public class OrderStatusListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("处理订单状态变更: {}", message);
        // 只处理 order_status tag 的消息
    }
}

4. 批量消费

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    consumerGroup = "batch-consumer",
    consumeThreadNumber = 10,  // 消费线程数
    consumeThreadMax = 20
)
public class BatchOrderListener implements RocketMQListener<List<MessageExt>> {

    @Override
    public void onMessage(List<MessageExt> messages) {
        log.info("批量收到消息, count: {}", messages.size());

        List<OrderDTO> orders = new ArrayList<>();
        for (MessageExt msg : messages) {
            String body = new String(msg.getBody(), StandardCharsets.UTF_8);
            OrderDTO order = JSON.parseObject(body, OrderDTO.class);
            orders.add(order);
        }

        // 批量处理
        batchProcessOrders(orders);
    }
}

高级特性

1. 消息幂等性

使用 key 实现幂等性:

@Service
public class OrderService {

    private final RocketMQSender rocketMQSender;
    private final RedisTemplate<String, String> redisTemplate;

    public void sendOrderMessageWithIdempotent(OrderDTO orderDTO) {
        String messageId = "ORDER_" + orderDTO.getOrderId();

        // 检查是否已处理
        Boolean processed = redisTemplate.hasKey("mq:processed:" + messageId);
        if (Boolean.TRUE.equals(processed)) {
            log.warn("消息已处理,跳过 - messageId: {}", messageId);
            return;
        }

        // 发送消息时设置key
        RocketMQMessage<OrderDTO> message = RocketMQMessage.<OrderDTO>builder()
            .topic("hotel-order-topic")
            .tag("order_create")
            .key(messageId)  // 用于幂等
            .message(orderDTO)
            .build();

        rocketMQSender.send(message);

        // 标记已处理
        redisTemplate.opsForValue().set("mq:processed:" + messageId, "1", 24, TimeUnit.HOURS);
    }
}

2. 消息追踪

使用 taskIdext 追踪消息链路:

@Service
public class TraceableOrderService {

    private final RocketMQSender rocketMQSender;

    public void sendTraceableOrder(OrderDTO orderDTO, String traceId) {
        RocketMQMessage<OrderDTO> message = RocketMQMessage.<OrderDTO>builder()
            .topic("hotel-order-topic")
            .tag("order_create")
            .message(orderDTO)
            .taskId(traceId)  // 设置追踪ID
            .putExt("traceId", traceId)
            .putExt("userId", orderDTO.getUserId())
            .putExt("clientIp", getClientIp())
            .putExt("timestamp", System.currentTimeMillis())
            .build();

        rocketMQSender.send(message);
    }
}

3. 消息重试

@Service
public class RetryableOrderService {

    private final RocketMQSender rocketMQSender;
    private static final int MAX_RETRY = 3;

    public void sendWithRetry(OrderDTO orderDTO) {
        sendWithRetry(orderDTO, 0);
    }

    private void sendWithRetry(OrderDTO orderDTO, int retryCount) {
        try {
            RocketMQMessage<OrderDTO> message = RocketMQSender.buildMessage(
                "hotel-order-topic",
                "order_create",
                orderDTO
            );
            rocketMQSender.send(message);
        } catch (Exception e) {
            if (retryCount < MAX_RETRY) {
                log.warn("消息发送失败,重试 {}/{} - orderId:{}",
                    retryCount + 1, MAX_RETRY, orderDTO.getOrderId());

                // 延迟重试
                try {
                    Thread.sleep(1000 * (retryCount + 1));
                } catch (InterruptedException ignored) {}

                sendWithRetry(orderDTO, retryCount + 1);
            } else {
                log.error("消息发送失败,已达最大重试次数 - orderId:{}",
                    orderDTO.getOrderId(), e);
                // 可以写入死信队列或数据库
                saveToDeadQueue(orderDTO);
            }
        }
    }
}

4. 事务消息(半消息)

@Service
public class TransactionalOrderService {

    private final RocketMQTemplate rocketMQTemplate;

    public void sendTransactionalMessage(OrderDTO orderDTO) {
        // 发送半消息
        rocketMQTemplate.sendMessageInTransaction(
            new TransactionListener() {
                @Override
                public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
                    try {
                        // 执行本地事务(创建订单)
                        createOrderInDB(orderDTO);
                        return LocalTransactionState.COMMIT_MESSAGE;
                    } catch (Exception e) {
                        log.error("本地事务执行失败", e);
                        return LocalTransactionState.ROLLBACK_MESSAGE;
                    }
                }

                @Override
                public LocalTransactionState checkLocalTransaction(MessageExt msg) {
                    // 回查本地事务状态
                    String orderId = msg.getKeys();
                    if (orderExistsInDB(orderId)) {
                        return LocalTransactionState.COMMIT_MESSAGE;
                    } else {
                        return LocalTransactionState.ROLLBACK_MESSAGE;
                    }
                }
            },
            MessageBuilder.withPayload(orderDTO).build(),
            null
        );
    }
}

延迟消息详解

RocketMQ 提供了 18 个延迟级别,可以满足大部分延迟场景。本项目提供了 RocketMQDelaySender 专门处理延迟消息。

1. 延迟级别枚举

public enum DelayLevel {
    OFF(0, "不延迟"),
    LEVEL_1(1, "1秒"),
    LEVEL_2(2, "5秒"),
    LEVEL_3(3, "10秒"),
    LEVEL_4(4, "30秒"),
    LEVEL_5(5, "1分钟"),
    LEVEL_6(6, "2分钟"),
    LEVEL_7(7, "3分钟"),
    LEVEL_8(8, "4分钟"),
    LEVEL_9(9, "5分钟"),
    LEVEL_10(10, "6分钟"),
    LEVEL_11(11, "7分钟"),
    LEVEL_12(12, "8分钟"),
    LEVEL_13(13, "9分钟"),
    LEVEL_14(14, "10分钟"),
    LEVEL_15(15, "20分钟"),
    LEVEL_16(16, "30分钟"),
    LEVEL_17(17, "1小时"),
    LEVEL_18(18, "2小时");
}

2. 使用延迟发送器

注入 RocketMQDelaySender

@Service
public class OrderService {

    private final RocketMQDelaySender delaySender;

    public OrderService(RocketMQDelaySender delaySender) {
        this.delaySender = delaySender;
    }
}

3. 发送延迟消息(指定级别)

@Service
public class PaymentTimeoutService {

    private final RocketMQDelaySender delaySender;

    // 发送30分钟后执行的支付超时检查
    public void sendPaymentTimeoutCheck(Long orderId) {
        Map<String, Object> body = new HashMap<>();
        body.put("orderId", orderId);
        body.put("checkType", "PAYMENT_TIMEOUT");

        RocketMQMessage<Map<String, Object>> message =
            RocketMQMessage.<Map<String, Object>>builder()
                .topic("hotel-order-topic")
                .tag("payment_timeout")
                .key("PAYMENT_TIMEOUT_" + orderId)
                .message(body)
                .build();

        // 延迟30分钟
        delaySender.sendDelay(message, DelayLevel.LEVEL_16);
    }
}

4. 自动计算延迟级别

按时间单位发送

@Service
public class FlexibleDelayService {

    private final RocketMQDelaySender delaySender;

    // 延迟45秒执行(自动选择 LEVEL_4: 30秒)
    public void sendDelayWithSeconds(RocketMQMessage<?> message) {
        delaySender.sendDelaySeconds(message, 45);
    }

    // 延迟15分钟执行(自动选择 LEVEL_15: 20分钟)
    public void sendDelayWithMinutes(RocketMQMessage<?> message) {
        delaySender.sendDelayMinutes(message, 15);
    }

    // 延迟3小时执行(自动选择 LEVEL_18: 2小时)
    public void sendDelayWithHours(RocketMQMessage<?> message) {
        delaySender.sendDelayHours(message, 3);
    }
}

5. 定时延迟消息(指定时间点执行)

@Service
public class ScheduledTaskService {

    private final RocketMQDelaySender delaySender;

    // 在指定时间点执行任务
    public void scheduleTaskAtTime(Long orderId, Date executeTime) {
        Map<String, Object> body = new HashMap<>();
        body.put("orderId", orderId);
        body.put("taskType", "SCHEDULED_TASK");

        RocketMQMessage<Map<String, Object>> message =
            RocketMQMessage.<Map<String, Object>>builder()
                .topic("hotel-order-topic")
                .tag("scheduled_task")
                .key("TASK_" + orderId)
                .message(body)
                .build();

        delaySender.sendDelayAt(message, executeTime);
    }
}

6. 业务场景封装

订单超时检查

@Service
public class OrderTimeoutService {

    private final RocketMQDelaySender delaySender;

    // 创建订单时发送30分钟后的超时检查
    public void createOrderWithTimeout(OrderDTO orderDTO) {
        // 1. 发送订单创建消息
        // ...

        // 2. 发送30分钟后的超时检查
        delaySender.sendOrderTimeoutCheck(orderDTO.getOrderId(), 30);
    }
}

支付超时检查

@Service
public class PaymentService {

    private final RocketMQDelaySender delaySender;

    // 用户下单时,发送支付超时检查消息
    public void waitForPayment(Long orderId, int timeoutMinutes) {
        delaySender.sendPaymentTimeoutCheck(orderId, timeoutMinutes);
    }
}

订单自动确认

@Service
public class OrderConfirmService {

    private final RocketMQDelaySender delaySender;

    // 订单完成后,24小时自动确认
    public void scheduleAutoConfirm(Long orderId) {
        delaySender.sendOrderAutoConfirm(orderId, 24);
    }
}

7. 延迟消息消费

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    selectorExpression = "payment_timeout || order_timeout",
    consumerGroup = "timeout-check-consumer"
)
public class TimeoutCheckListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("收到超时检查消息: {}", message);

        Map<String, Object> msgMap = JSON.parseObject(message, Map.class);
        String checkType = (String) msgMap.get("checkType");
        Long orderId = (Long) msgMap.get("orderId");

        switch (checkType) {
            case "PAYMENT_TIMEOUT":
                handlePaymentTimeout(orderId);
                break;
            case "ORDER_TIMEOUT":
                handleOrderTimeout(orderId);
                break;
            case "AUTO_CONFIRM":
                handleAutoConfirm(orderId);
                break;
        }
    }

    private void handlePaymentTimeout(Long orderId) {
        // 检查订单支付状态
        // 如果未支付,自动取消订单
    }

    private void handleOrderTimeout(Long orderId) {
        // 处理订单超时逻辑
    }

    private void handleAutoConfirm(Long orderId) {
        // 自动确认订单
    }
}

事务消息详解

RocketMQ 事务消息用于实现分布式事务的一致性,保证本地事务和消息发送的原子性。

1. 事务消息原理

1. 发送半消息(Half Message)- 消息对消费者不可见
2. 执行本地事务
3. 提交事务状态
   - 成功:提交消息(Commit)- 消息对消费者可见
   - 失败:回滚消息(Rollback)- 删除消息
   - 未知:回查状态(Check)- MQ主动查询本地事务状态

2. 使用事务发送器

注入 RocketMQTransactionSender

@Service
public class TransactionalOrderService {

    private final RocketMQTransactionSender txSender;

    public TransactionalOrderService(RocketMQTransactionSender txSender) {
        this.txSender = txSender;
    }
}

3. 发送事务消息(使用执行器)

@Service
public class OrderService {

    private final RocketMQTransactionSender txSender;
    private final OrderRepository orderRepository;

    @Transactional
    public void createOrderTransactional(final OrderDTO orderDTO) {
        // 构建事务消息
        RocketMQMessage<OrderDTO> message =
            RocketMQTransactionSender.buildTransactionMessage(
                "hotel-order-topic",
                "order_create",
                "ORDER_" + orderDTO.getOrderId(),
                orderDTO
            );

        // 发送事务消息
        txSender.sendTransactionMessage(message, new RocketMQTransactionSender.LocalTransactionExecutor<OrderDTO>() {

            @Override
            public void execute(OrderDTO msg) throws Exception {
                // 执行本地事务:创建订单
                log.info("执行本地事务 - 创建订单: {}", msg.getOrderId());
                Order order = new Order();
                order.setOrderId(msg.getOrderId());
                order.setOrderNo(msg.getOrderNo());
                orderRepository.save(order);
            }

            @Override
            public boolean check(OrderDTO msg) throws Exception {
                // 回查本地事务状态:检查订单是否存在
                log.info("回查本地事务状态 - 检查订单: {}", msg.getOrderId());
                return orderRepository.existsById(msg.getOrderId());
            }
        });
    }
}

4. 事务消息消费

@Component
@RocketMQMessageListener(
    topic = "hotel-order-topic",
    selectorExpression = "order_create",
    consumerGroup = "order-event-consumer"
)
public class OrderEventListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        log.info("收到订单事件消息: {}", message);

        OrderDTO orderDTO = JSON.parseObject(message, OrderDTO.class);

        // 处理订单后续逻辑
        // 例如:通知其他服务、触发工作流等
        notifyOtherServices(orderDTO);
    }
}

5. 典型应用场景

场景1:订单创建 + 库存扣减

@Service
public class OrderInventoryService {

    private final RocketMQTransactionSender txSender;
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;

    /**
     * 创建订单并扣减库存(事务消息)
     */
    public void createOrderWithInventory(final OrderDTO orderDTO) {
        RocketMQMessage<OrderDTO> message =
            RocketMQTransactionSender.buildTransactionMessage(
                "hotel-order-topic",
                "order_create",
                "ORDER_" + orderDTO.getOrderId(),
                orderDTO
            );

        txSender.sendTransactionMessage(message, new RocketMQTransactionSender.LocalTransactionExecutor<OrderDTO>() {

            @Override
            public void execute(OrderDTO msg) throws Exception {
                // 本地事务:创建订单 + 扣减库存
                // 1. 创建订单
                Order order = new Order();
                order.setOrderId(msg.getOrderId());
                orderRepository.save(order);

                // 2. 扣减库存
                inventoryService.deduct(msg.getHotelId(), msg.getRoomCount());

                // 如果任何一步失败,抛出异常,消息会被回滚
            }

            @Override
            public boolean check(OrderDTO msg) throws Exception {
                // 回查:订单和库存状态
                return orderRepository.existsById(msg.getOrderId());
            }
        });
    }
}

场景2:支付成功 + 订单状态更新

@Service
public class PaymentOrderService {

    private final RocketMQTransactionSender txSender;
    private final PaymentRepository paymentRepository;
    private final OrderRepository orderRepository;

    /**
     * 支付成功后更新订单状态(事务消息)
     */
    public void paymentSuccess(final PaymentDTO paymentDTO) {
        RocketMQMessage<PaymentDTO> message =
            RocketMQTransactionSender.buildTransactionMessage(
                "hotel-order-topic",
                "payment_success",
                "PAYMENT_" + paymentDTO.getPaymentId(),
                paymentDTO
            );

        txSender.sendTransactionMessage(message, new RocketMQTransactionSender.LocalTransactionExecutor<PaymentDTO>() {

            @Override
            public void execute(PaymentDTO msg) throws Exception {
                // 本地事务:
                // 1. 更新支付状态
                paymentRepository.updateStatus(msg.getPaymentId(), "SUCCESS");

                // 2. 更新订单状态
                orderRepository.updateStatus(msg.getOrderId(), "PAID");
            }

            @Override
            public boolean check(PaymentDTO msg) throws Exception {
                // 回查:支付和订单状态
                return "SUCCESS".equals(paymentRepository.getStatus(msg.getPaymentId()));
            }
        });
    }
}

6. 事务消息注意事项

注意事项说明
幂等性消费者需要实现幂等性,因为事务消息可能重复消费
回查机制本地事务执行器需要实现 check() 方法,用于 MQ 回查
超时时间事务消息的超时时间由 transactionTimeout 配置决定
线程安全本地事务执行器需要保证线程安全
异常处理execute() 抛出异常会导致消息回滚,需谨慎处理

7. 配置事务消息

application.yml

rocketmq:
  producer:
    # 事务消息超时时间(毫秒)
    transaction-timeout: 300000
    # 最大重试次数
    retry-times-when-send-failed: 2

最佳实践

1. Topic 和 Tag 设计

命名规范

Topic: {业务线}-{功能}
Tag: {模块}_{操作}

示例

✅ 推荐:
Topic: hotel-order
Tag: order_create
Tag: order_cancel
Tag: order_status_update

❌ 不推荐:
Topic: topic1
Tag: tag

2. 消息体设计

// ✅ 推荐:使用专用的DTO
public class OrderCreatedEvent {
    private Long orderId;
    private String orderNo;
    private Long userId;
    private BigDecimal amount;
    private LocalDateTime createTime;
}

// ❌ 不推荐:使用Map
Map<String, Object> body = new HashMap<>();
body.put("orderId", orderId);
body.put("orderNo", orderNo);

3. 消费者处理

@Component
public class BestPracticeListener implements RocketMQListener<String> {

    @Override
    public void onMessage(String message) {
        try {
            // 1. 参数校验
            if (StringUtils.isEmpty(message)) {
                log.warn("空消息,跳过");
                return;
            }

            // 2. 幂等性检查
            String msgKey = extractKey(message);
            if (isProcessed(msgKey)) {
                log.info("消息已处理,跳过 - key:{}", msgKey);
                return;
            }

            // 3. 业务处理
            processMessage(message);

            // 4. 标记已处理
            markAsProcessed(msgKey);

        } catch (BusinessException e) {
            // 业务异常,记录日志但不抛出异常
            log.error("业务处理失败 - message:{}", message, e);
        } catch (Exception e) {
            // 系统异常,抛出异常触发重试
            log.error("系统异常,将重试 - message:{}", message, e);
            throw e;
        }
    }
}

4. 性能优化

# 生产者配置优化
rocketmq:
  producer:
    # 压缩阈值,超过4KB自动压缩
    compress-message-body-threshold: 4096
    # 批量发送大小
    max-message-size: 4194304

  consumer:
    # 消费线程数
    consume-thread-min: 20
    consume-thread-max: 64
    # 批量消费
    consume-message-batch-max-size: 1
// 批量发送示例
@Service
public class PerformanceOptimizedService {

    private final RocketMQSender rocketMQSender;

    public void batchSend(List<OrderDTO> orders) {
        // 按100条一批发送
        Lists.partition(orders, 100).forEach(batch -> {
            RocketMQMessage<OrderDTO> message = RocketMQSender.buildBatchMessage(
                "hotel-order-topic",
                "order_batch",
                batch
            );
            rocketMQSender.sendBatch(message);
        });
    }
}

常见问题

Q1: 消息发送失败怎么办?

A: 实现重试机制

@Service
public class RetryService {

    private final RocketMQSender rocketMQSender;

    @Retryable(
        value = {MQException.class},
        maxAttempts = 3,
        backoff = @Backoff(delay = 1000, multiplier = 2)
    )
    public void sendWithRetry(RocketMQMessage<?> message) {
        rocketMQSender.send(message);
    }
}

Q2: 如何保证消息不丢失?

A: 使用同步发送 + 持久化日志

@Service
public class ReliableMessageService {

    private final RocketMQSender rocketMQSender;
    private final MessageLogRepository logRepository;

    @Transactional
    public void sendReliableMessage(OrderDTO orderDTO) {
        // 1. 先保存消息日志
        MessageLog log = new MessageLog();
        log.setTopic("hotel-order-topic");
        log.setTag("order_create");
        log.setBody(JSON.toJSONString(orderDTO));
        log.setStatus("SENDING");
        logRepository.save(log);

        try {
            // 2. 发送消息
            RocketMQMessage<OrderDTO> message = RocketMQSender.buildMessage(
                "hotel-order-topic",
                "order_create",
                orderDTO
            );
            SendResult result = rocketMQSender.send(message);

            // 3. 更新日志状态
            log.setStatus("SENT");
            log.setMsgId(result.getMsgId());
            logRepository.save(log);
        } catch (Exception e) {
            // 发送失败,更新状态
            log.setStatus("FAILED");
            log.setErrorMessage(e.getMessage());
            logRepository.save(log);
            throw e;
        }
    }
}

Q3: 消息消费积压怎么处理?

A: 增加消费者实例和线程数

rocketmq:
  consumer:
    # 增加消费线程
    consume-thread-min: 50
    consume-thread-max: 100
# 水平扩展:启动多个消费者实例
# 注意:同组消费者会负载均衡,不同组消费者会广播
java -jar order-justgotrip-job.jar --server.port=9003
java -jar order-justgotrip-job.jar --server.port=9004
java -jar order-justgotrip-job.jar --server.port=9005