Rocketmq分布式事物消息

Rocketmq源码中关于分布式事物消息的实现并没有完全开源,本人是基于3.4.6分析。其中的类是TransactionMQProducer。

源码分析
  1. TransactionMQProducer是发送分布式事物消息的核心基础类,其中sendMessageInTransaction是主要发送方法。该方法的核心步骤主要有3步。
    1.1. producer发送一条prepared消息至broker.
    1.2. 调用LocalTransactionExecutor执行本地业务逻辑,提交事物。
    1.3. 本地事物提交之后,发送事物确认消息。
  2. 分析一下sendMessageInTransaction源码
 public TransactionSendResult sendMessageInTransaction(final Message msg,final LocalTransactionExecuter tranExecuter, final Object arg) throws MQClientException {
       // 1. tranExecutor,需要应用自己开发实现
        if (null == tranExecuter) {
            throw new MQClientException("tranExecutor is null", null);
        }
      // 2. 检查消息各种属性和装填
        Validators.checkMessage(msg, this.defaultMQProducer);
        SendResult sendResult = null;
       // 3.1 设置发送消息属性类型,事物预备消息 
        MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true");
       // 3.2 设置消息所属的group
       MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP,
            this.defaultMQProducer.getProducerGroup());
        try {
        // 4. 发送预备消息
            sendResult = this.send(msg);
        }
        catch (Exception e) {
            throw new MQClientException("send message Exception", e);
        }
        // 5. 初始化本地事物装填--UNKNOW未知状态
        LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;
        Throwable localException = null;
        // 6. 判断发送预备消息的状态
        switch (sendResult.getSendStatus()) {
        case SEND_OK: {
        try {
            if (sendResult.getTransactionId() != null) {        msg.putUserProperty("__transactionId__",sendResult.getTransactionId());
             }
        // 7. 执行本地事物逻辑,用户自己实现的业务逻辑部分
        localTransactionState = tranExecuter.executeLocalTransactionBranch(msg, arg);
        if (null == localTransactionState) {
            localTransactionState = LocalTransactionState.UNKNOW;
          }
        // 8.判断本地事物状态    
        if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE) {
           log.info("executeLocalTransactionBranch return {}", localTransactionState);
             log.info(msg.toString());
           }
         }catch (Throwable e) {
            log.info("executeLocalTransactionBranch exception", e);
            log.info(msg.toString());
            localException = e;
         }
      }
        break;
        case FLUSH_DISK_TIMEOUT:
        case FLUSH_SLAVE_TIMEOUT:
        case SLAVE_NOT_AVAILABLE:
            localTransactionState = LocalTransactionState.ROLLBACK_MESSAGE;
            break;
        default:
            break;
        }
    // 9 根据本地事物状态,发送事物确认消息。
        try {
            this.endTransaction(sendResult, localTransactionState, localException);
        }
        catch (Exception e) {
            log.warn("local transaction execute " + localTransactionState
                    + ", but end broker transaction failed", e);
        }
    // 1. 构建返回发送事物结果
        TransactionSendResult transactionSendResult = new TransactionSendResult();
        transactionSendResult.setSendStatus(sendResult.getSendStatus());
        transactionSendResult.setMessageQueue(sendResult.getMessageQueue());
        transactionSendResult.setMsgId(sendResult.getMsgId());
        transactionSendResult.setQueueOffset(sendResult.getQueueOffset());
        transactionSendResult.setTransactionId(sendResult.getTransactionId());
        transactionSendResult.setLocalTransactionState(localTransactionState);
        return transactionSendResult;
    }
  1. 分析一下endTransaction源码
 private void endTransaction(//
            final SendResult sendResult, //
            final LocalTransactionState localTransactionState, //
            final Throwable localException) throws RemotingException, MQBrokerException,InterruptedException, UnknownHostException {
        // 消息ID
        final MessageId id = MessageDecoder.decodeMessageId(sendResult.getMsgId());
        // 事物ID
        String transactionId = sendResult.getTransactionId();
        // 获取brokerAddr
        final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName());
       // 构建确认事物请求头信息
        EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader();
        // 设置事物请求ID
        requestHeader.setTransactionId(transactionId);
        // 设置消息的偏移量offset
        requestHeader.setCommitLogOffset(id.getOffset());
        // 判断本地事物状态
        switch (localTransactionState) {
        case COMMIT_MESSAGE:
    /**设置成功消息类型**/       requestHeader.setCommitOrRollback(MessageSysFlag.TransactionCommitType);
            break;
        case ROLLBACK_MESSAGE:
 /**设置回滚消息类型**/            requestHeader.setCommitOrRollback(MessageSysFlag.TransactionRollbackType);
            break;
        case UNKNOW:
            requestHeader.setCommitOrRollback(MessageSysFlag.TransactionNotType);
            break;
        default:
            break;
        }

        requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup());
        requestHeader.setTranStateTableOffset(sendResult.getQueueOffset());
        requestHeader.setMsgId(sendResult.getMsgId());
        String remark =
                localException != null ? ("executeLocalTransactionBranch exception: " + localException
                    .toString()) : null;
 /**发送事物确认消息**/       this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark,
            this.defaultMQProducer.getSendMsgTimeout());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值