RocektMQ事务
一、简介
RocketMQ是一种最终一致性的分布式事务,就是说它保证的是消息最终一致性。
A、MQ发送方先发送个Half Message给Broker端,消息中携带MQ订阅方需要的消息。
B、当MQ发送方知道Half Message发送成功后,那么开始第C步执行本地事务。
C、执行本地事务(会有三种情况1、执行成功。2、执行失败。3、网络等原因导致没有响应)
D、如果本地事务成功,那么Product向Broker服务器发送Commit,这样MQ订阅方就可以消费该message;如果本地事务失败,那么Product向Broker服务器发送Rollback,那么就会直接删除上面这条半消息。
E、如果因为网络等原因迟迟没有返回失败还是成功,那么会执行RocketMQ的回调接口,来进行事务的回查。
F、检查本地事务状态。
G、根据第F步检查的状态反馈给Broker,Commit即投递消息到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); } } }
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; } }
说明:
A、executeLocalTransaction方法中可执行本地事务,其返回状态可为COMMIT(事务提交)、ROLLBACK(事务回滚)、UNKNOWN(未知),如果为UNKNOWN状态或者没有返回状态会进入checkLocalTransaction方法,即检查本地事务的执行状态方法。
B、checkLocalTransaction方法为检查本地事务方法其返回值为COMMIT(事务提交)、ROLLBACK(事务回滚)、UNKNOWN(未知),如果为UNKNOWN状态则下一次检查时还会进入此方法检测本地事务,默认检查间隔为6000ms,检查次数为15次。
C、checkLocalTransaction方法中也可以定义检测次数,如三次,可存为Redis中,key为事务id,value为次数,如果到达三次那么直接返回ROLLBACK.