RocketMQ笔记-事务消息

事务消息实现思想

RocketMQ 事务消息,是指发送消息事件和其他事件需要同时成功或同失败。比如银行转账, A 银行的某账户要转一万元到 B 银行的某账户。A 银 行发送“B 银行账户增加一万元” 这个消息,要和“从 A 银行账户扣除一万元”这个操作同时成功或者同时失败。

RocketMQ 采用两阶段提交的方式实现事务消息,TransactionMQProducer 处理上面情况的流程是,先发一个“准备从 B 银行账户增加一万元”的消息,发送成功后做从 A 银行账户扣除一万元的操作 ,根据操作结果是否成功,确定之前的“准备从 B 银行账户增加一万元”的消息是做 commit 还是 rollback , RocketMQ 实现的具体流程如下:
在这里插入图片描述

  1. 发送方向 RocketMQ 发送“待确认”(Prepare)消息
  2. RocketMQ 将收到的“待确认”(一般写入一个 HalfTopic 主题<RMQ_SYS_TRANS_HALF_TOPIC>)消息持化成功后, 向发送方回复消息已经发送成功,此时第一阶段消息发送完成。
    发送方开始执行本地事件逻辑.
  3. 送方根据事件执行结果向 RocketMQ 发送二次确认( Commit 还是 Rollback)消息 RocketMQ 收到 Commit 则将第一阶段消息标记为可投递(这些 消息才会进入生产时发送实际的主题 RealTopic),订阅方将能够收到该消息;收到 Rollback 状态则删除第一阶段的消息,订阅方接收不到该消息。
  4. 如果出现异常情况,步骤 3 提交的二次确认最终未到达 RocketMQ,服务器在经过固定时间段后将对“待确认”消息、发起回查请求.
  5. 发送方收到消息回查请求后(如果发送一阶段消息的 Producer 不能工作,回查请求将被发送到和 Producer 在同一个 Group 里的其他 Producer ), 通过检查对应消息的本地事件执行结果返回 Commit Roolback 状态。

事务状态回查机制

RocketMQ 通过 TransactionalMessageCheckService 线程定时去检测 RMQ_SYS_ TRANS_ HALF_TOPIC 主题中的消息,回查消息的事务状态 TransactionalMessageCheckService 的检测频率默认为 1 分钟,可通过在 broker.conf 文件中设置 transactionChecklnterval 来改变默认值,单位为毫秒。

代码实现

 TransactionListener transactionListener = new TransactionListenerImpl();

 TransactionMQProducer producer = new TransactionMQProducer("transaction_group");
 producer.setNamesrvAddr("localhost:9876");
 producer.setSendMsgTimeout(10000);
 producer.setTransactionListener(transactionListener);
 ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
     @Override
     public Thread newThread(Runnable r) {
         Thread thread = new Thread(r);
         thread.setName("client-transaction-msg-check-thread");
         return thread;
     }
 });

 producer.setExecutorService(executorService);
 producer.start();

 for (int i = 0; i < 10; i++) {
     Message message = new Message("topic_bank",
             "TagA",
             ("银行转账"+i).getBytes(RemotingHelper.DEFAULT_CHARSET));
     producer.sendMessageInTransaction(message,null);

     System.out.printf("%s%n",new String(message.getBody()));
 }
public class TransactionListenerImpl implements TransactionListener {
    private AtomicInteger transactionIndex = new AtomicInteger(0);

    private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();

    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
    	//业务处理
        int value = transactionIndex.getAndIncrement();
        int status = value % 3;
        localTrans.put(msg.getTransactionId(), status);
        return LocalTransactionState.UNKNOW;
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        Integer status = localTrans.get(msg.getTransactionId());
        if (null != status) {
            switch (status) {
                case 0:
                    return LocalTransactionState.UNKNOW;
                case 1:
                    return LocalTransactionState.COMMIT_MESSAGE;
                case 2:
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                default:
                    return LocalTransactionState.COMMIT_MESSAGE;
            }
        }
        return LocalTransactionState.COMMIT_MESSAGE;
    }
}

LocalTransactionState 枚举类
COMMIT_MESSAGE 提交消息,即 broker 确认了这条消息的正确性之后执行提交,标记这条消息可被消费,这样的话 consumer 就可以正常消费这 条消息了;
ROLLBACK_MESSAGE 回滚消息,意思是当我们的本地主事务发生异常的时候,回滚本地事务的同时,同样需要一种方法通知到 rocketMq 不要继续发 送消息了,当 broker 收到这个命令时候就会标记消息为 rollBack 的状态,consumer 就不能收到了
UNKNOW 消息回查的状态

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值