RocketMQ的事务消息模式

1. 事务消息简介

即,在分布式系统中保证最终一致性的两阶段提交的消息实现。

侧重点:保证本地事务执行消息发送两个操作的原子性

2. 事务消息发送流程

  1. 消息生产者向Broker投递一个half(事务)消息(如需保证幂等性,可以携带一个唯一的key作为参数)
  2. 确认Broker接收到消息(消息会在Broker本地进行存储,但是该消息的状态对消费者不可见)
  3. 生产者确认消息发送成功后,回调executeLocalTransaction方法来执行本地事务
  4. 生产者提交本地事务的执行状态
  5. Broker进行最终处理

过程中可能的情况:

  • 第4步提交事务成功状态,Broker将消息投递到消费者
  • 第4步提交事务失败(回滚)状态,Broker丢弃该消息
  • 第4步提交超时时,Broker会定时回查
    在这里插入图片描述

3. 代码实现

package com.example.mq.transaction;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;


/**
 * 描述:
 * 事务消息监听器
 *
 * @author XueGuCheng
 * @create 2021-03-30 21:59
 */
public class TransactionListenerImpl implements TransactionListener {

    /**
     * 提交完事务消息后执行此方法
     * 返回COMMIT_MESSAGE(正常提交)状态的消息会立即被消费者消费到
     * 返回ROLLBACK_MESSAGE(回滚)状态的消息会被丢弃
     * 返回UNKNOWN(消息状态未知,因为网络等原因)状态的消息会由Broker过一段时间再来回查事务的状态
     *
     * @param message 消息内容
     * @param o
     * @return
     */
    @Override
    public LocalTransactionState executeLocalTransaction(Message message, Object o) {
        // 编写业务逻辑
        /*
            业务逻辑:根据消息携带的不同的Tag属性进行不同的业务操作
                        Tag_A的消息会提交,即立即被消费者消费到
                        Tag_B的消息会回滚,即会被丢弃
                        其他Tag属性消息会被标记为未知状态,等待Broker进行事务状态回查
         */
        String tags = message.getTags();
        if (StringUtils.contains(tags, "Tag_A")) {
            return LocalTransactionState.COMMIT_MESSAGE;
        } else if (StringUtils.contains(tags, "Tag_B")) {
            return LocalTransactionState.ROLLBACK_MESSAGE;
        } else {
            return LocalTransactionState.UNKNOW;
        }

    }

    /**
     * 对UNKNOWN状态的消息进行事务状态回查
     *
     * @param messageExt UNKNOWN状态的消息
     * @return 事务状态
     */
    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
        // 编写业务逻辑
         /*
            业务逻辑:根据消息携带的不同的Tag属性进行不同的业务操作
                        回查时,Tag_C的消息会提交,即会被消费者消费到
                        回查时,Tag_D的消息会回滚,即会被丢弃
                        回查时,其他Tag属性消息会在多次回查(默认15次)后,最终丢弃
         */
        String tags = messageExt.getTags();
        if (StringUtils.contains(tags, "Tag_C")) {
            return LocalTransactionState.COMMIT_MESSAGE;
        } else if (StringUtils.contains(tags, "Tag_D")) {
            return LocalTransactionState.ROLLBACK_MESSAGE;
        } else {
            return LocalTransactionState.UNKNOW;
        }

    }
}

4. 事务消息的限制

  1. 不支持延迟消息和批量消息
  2. 消息回查次数默认15次,为了防止消息回查次数太多次而导致消息累积。可以配置 Broker 的配置文件的 transactionCheckMax 参数来修该回查次数,回查次数超过该参数时, Broker 将丢弃此消息,并在默认情况下同时打印错误日志,可以通过重 AbstractTransactionCheckListener 类来修改这个行为
  3. 多久后进行回查?超时时间在Broker 的配置文件的 transactionMsgTimeout 参数进行设置,也可以在发送事务消息时,配置用户属性 CHECK_IMMUNITY_TIME_IN_SECONDS 来进行设置(该设置优先级高于transactionMsgTimeout 参数)
  4. 多次消费,即事务性消息可能不止一次被检查或消费
  5. 事务消息的生产者 ID 不能与其他类型消息的生产者 ID 共享,因为事务消息会进行回查

5. 总结

RocketMQ的事务消息模式息只保证了发送者本地事务和发送消息这两个操作的原子性,并没有保证分布式系统下的两个事务的一致性(下游事务失败或者回滚,上游事务是感知不到的)。所以,事务消息模式只保证了分布式事务的一半的一致性。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值