RocektMQ事务

一、简介

RocketMQ是一种最终一致性的分布式事务,就是说它保证的是消息最终一致性

 

 

 

 

A、MQ发送方先发送个Half MessageBroker端,消息中携带MQ订阅方需要的消息。

B、当MQ发送方知道Half Message发送成功后,那么开始第C步执行本地事务。

C、执行本地事务(会有三种情况1、执行成功。2、执行失败。3、网络等原因导致没有响应)

D、如果本地事务成功,那么ProductBroker服务器发送Commit,这样MQ订阅方就可以消费该message;如果本地事务失败,那么ProductBroker服务器发送Rollback,那么就会直接删除上面这条半消息。

E、如果因为网络等原因迟迟没有返回失败还是成功,那么会执行RocketMQ的回调接口,来进行事务的回查。

F、检查本地事务状态。

G、根据第F步检查的状态反馈给BrokerCommit即投递消息到MQ订阅方,Rollback即删除消息。

二、代码

 

public class OrderService {
  public static void main(String[] args) throws Exception {
    TransactionMQProducer producer = new TransactionMQProducer();
    producer.setNamesrvAddr(RocketMQConstants.NAMESRV_ADDR);
    producer.setProducerGroup(RocketMQConstants.TRANSACTION_PRODUCER_GROUP);

    //自定义线程池,执行事务操作
    ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 50, 10L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20), (Runnable r) -> new Thread("Order Transaction Massage Thread"));
    producer.setExecutorService(executor);

    //设置事务消息监听器
    producer.setTransactionListener(new OrderTransactionListener());

    producer.start();

    System.err.println("OrderService Start");

    for (int i = 0;i < 10;i++){
      String orderId = UUID.randomUUID().toString();
      String payload = "下单,orderId: " + orderId;
      String tags = "Tag";
      Message message = new Message(RocketMQConstants.TRANSACTION_TOPIC_NAME, tags, orderId, payload.getBytes(RemotingHelper.DEFAULT_CHARSET));

      //发送事务消息
      TransactionSendResult result = producer.sendMessageInTransaction(message, orderId);
      System.err.println("发送事务消息,发送结果: " + result);
    }
  }
}
View Code

 

public class OrderTransactionListener implements TransactionListener {
  private static final Map<String, Boolean> results = new ConcurrentHashMap<>();

  @Override
  public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
    String orderId = (String) arg;

    //记录本地事务执行结果
    boolean success = persistTransactionResult(orderId);
    System.err.println("订单服务执行本地事务下单,orderId: " + orderId + ", result: " + success);
    return success ? LocalTransactionState.COMMIT_MESSAGE : LocalTransactionState.ROLLBACK_MESSAGE;
  }

  @Override
  public LocalTransactionState checkLocalTransaction(MessageExt msg) {
    String orderId = msg.getKeys();
    System.err.println("执行事务消息回查,orderId: " + orderId);
    return Boolean.TRUE.equals(results.get(orderId)) ? LocalTransactionState.COMMIT_MESSAGE : LocalTransactionState.ROLLBACK_MESSAGE;
  }

  private boolean persistTransactionResult(String orderId) {
    boolean success = Math.abs(Objects.hash(orderId)) % 2 == 0;
    results.put(orderId, success);
    return success;
  }
}
View Code

说明:

A、executeLocalTransaction方法中可执行本地事务,其返回状态可为COMMIT(事务提交)、ROLLBACK(事务回滚)、UNKNOWN(未知),如果为UNKNOWN状态或者没有返回状态会进入checkLocalTransaction方法,即检查本地事务的执行状态方法。

B、checkLocalTransaction方法为检查本地事务方法其返回值为COMMIT(事务提交)、ROLLBACK(事务回滚)、UNKNOWN(未知),如果为UNKNOWN状态则下一次检查时还会进入此方法检测本地事务,默认检查间隔为6000ms,检查次数为15次。

C、checkLocalTransaction方法中也可以定义检测次数,如三次,可存为Redis中,key为事务idvalue为次数,如果到达三次那么直接返回ROLLBACK.

 

posted @ 2021-05-24 12:06  TimeSay  阅读(120)  评论(0编辑  收藏  举报