3 - トランザクションメッセージを注意してくださいRocketMQ

トランザクションメッセージの紹介

  • RocketMQトランザクションメッセージ(トランザクションメッセージ)ローカルトランザクションのアプリケーションであり、成功または失敗のいずれかを同時にしながら、オペレータにメッセージを送信することは、グローバルトランザクションに定義されてもよいです。RocketMQトランザクションメッセージは、X / Open XA、最終取引メッセージに似た分散トランザクション機能は、分散トランザクションの全会一致採択に到達することができます。

プロセス

  • ステージ(送信メッセージを、ローカル・トランザクション・ステータス・メッセージより多くの行を実行します)
    • メッセージを送信する(半分メッセージ)
    • サーバーの応答メッセージの書き込み結果
    • ローカルトランザクション送信結果に従って実行(書き込みが失敗した場合、その後、半分目に見えないメッセージサービス、ローカルロジックが実行されません)
    • ロールバックまたはローカル状態に基づいて、トランザクションをコミットし(オペレーションがメッセージ指数、消費者に目に見えるメッセージをコミット生成)
  • ステージ2(補償)
    • トランザクションメッセージは、サーバから「バックチェック」を起動し、/ロールバック(メッセージ保留状態)にコミットされていません
    • プロデューサー対応するローカル業務をチェックするために戻ってステータスメッセージを確認し、確認するために戻ってメッセージを受け取ります
    • ローカルトランザクション状態、再コミットまたはロールバック
      ケースを解決するための補償ステージは、メッセージのタイムアウトまたは失敗をコミットまたはロールバック前記起こります。
  • 詳細なプロセスは、参考文献に行くことができます

トランザクションメッセージを使用します

  • トランザクションプロデューサー
@Component
public class MqProducer {

    @Value("${mq.nameserver.addr}")
    private String nameAddr;

    @Value("${mq.topicname}")
    private String topicName;

    //事务型生成者
    private TransactionMQProducer transactionMQProducer;

    @PostConstruct
    public void init() throws MQClientException {
        transactionMQProducer=new TransactionMQProducer("transaction_producer_group");
        //设置nameSrv
        transactionMQProducer.setNamesrvAddr(nameAddr);
        
        //开启事务型生产者
        transactionMQProducer.start();
        
        //监听本地事务(关键),可以自定义一个类实现  TransactionListener  接口,或是通过匿名内部类
        transactionMQProducer.setTransactionListener(new TransactionListener() {
             /*
                 执行本地事务
            */
            @Override
            public LocalTransactionState executeLocalTransaction(Message message, Object args) {                
                try {
                   //执行本地事务
                } catch (Exception e) {
                    e.printStackTrace();
                    //当执行到这里,说明本地事务执行异常,回滚
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
                //执行本地事务成功,提交
                return LocalTransactionState.COMMIT_MESSAGE;
            }
            
            /*
                 回查方法
            */
            @Override
            public LocalTransactionState checkLocalTransaction(MessageExt msg) {
                //当LocalTransaction无法更新prepared消息,会通过这个方法执行本地策略
                if(判断1){
                    //说明本地事务执行成功,提交
                    return LocalTransactionState.COMMIT_MESSAGE;
                }else if(判断2){
                    //无法判断原因,当消息为UNKNOW时,会定时回查
                    return LocalTransactionState.UNKNOW;
                }else{
                    //其他则一律回滚
                    return LocalTransactionState.ROLLBACK_MESSAGE;
                }
            }
        });
    }

     /*
            发送消息
     */
    public boolean sendMessage(Integer userId,Integer itemId,Integer amount,Integer promoId,String stockLogId){  
        Map<String,Object> mapArgs= new HashMap<>();
        mapArgs.put("key",value);;

        Message message=new Message(topicName,"Tag", "message");

        TransactionSendResult transactionSendResult=null;
        try {
             transactionSendResult = transactionMQProducer.sendMessageInTransaction(message, mapArgs);
        } catch (MQClientException e) {
            e.printStackTrace();
            return false;
        }
        if(transactionSendResult.getLocalTransactionState() == LocalTransactionState.COMMIT_MESSAGE){
            return true;
        }else if(transactionSendResult.getLocalTransactionState() == LocalTransactionState.ROLLBACK_MESSAGE){
            return false;
        }else {
            return false;
        }
    }
}

  • 消費者
public class Consumer {
    public static void main(String[] args) throws MQClientException {
        //创建消费者对象
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test_consumerGroup");
        
        //设置NamesrvAddr 及消费位置ConsumeFromWhere
        consumer.setNamesrvAddr(Const.NAMESRV_ADDR);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        
        //订阅topic,  * 指该主题下的所有消息都能消费
        consumer.subscribe("test_topic","*");
        
        //注册监听并消费
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                //获取消息
                MessageExt msg = list.get(0);
                try {
                        //可以根据消息来执行其他业务,达到和本地事务的最终一致性
                }catch (Exception e){
                    e.printStackTrace();
                    int reconsumeTimes = msg.getReconsumeTimes();
                    if(reconsumeTimes == 2){
                        //记录日志,补偿处理
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    }
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;//重试
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //启动消费服务
        System.out.println("消费服务启动...");
        consumer.start();
    }
}

参照

おすすめ

転載: www.cnblogs.com/wuba/p/11772953.html