消息中间件RocketMq之事务消息
分布式系统中的事务可以使用TCC(Try、Confirm、Cancel)、2pc来解决分布式系统中的消息原子性
RocketMQ 4.3+提供分布事务功能,通过 RocketMQ 事务消息能达到分布式事务的最终一致
RocketMQ实现方式
2PC
- Half Message:
预处理消息,当broker收到此类消息后,会存储到RMQ_SYS_TRANS_HALF_TOPIC的消息消费队列中
- 检查事务状态:
Broker会开启一个定时任务,消费RMQ_SYS_TRANS_HALF_TOPIC队列中的消息,每次执行任务会向消息发送者确认事务执行状态(提交、回滚、未知),因此需要定义check的接口。如果是未知,等待下一次回调。。
本地执行完了,就会commit,修改事务状态
- 超时:
如果超过回查次数,默认回滚消息
TransactionListener的两个方法
executeLocalTransaction
半消息发送成功触发此方法来执行本地事务
checkLocalTransaction
broker将发送检查消息来检查事务状态,并将调用此方法来获取本地事务状态
本地事务执行状态
LocalTransactionState.COMMIT_MESSAGE
执行事务成功,确认提交
LocalTransactionState.ROLLBACK_MESSAGE
回滚消息,broker端会删除半消息
LocalTransactionState.UNKNOW
暂时为未知状态,等待broker回查
使用
public static void main(String[] args) throws Exception {
TransactionMQProducer producer = new TransactionMQProducer("transgroup");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
// 执行本地事务
System.out.println("执行事务");
System.out.println("msg:" + new String(message.getBody()));
System.out.println("msgid:" + message.getTransactionId());
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行事务完成");
return LocalTransactionState.COMMIT_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt message) {
// broker 端 回调检查事务
System.out.println("回调检查事务");
System.out.println("msg:" + new String(message.getBody()));
System.out.println("msgid:" + message.getTransactionId());
// 失败回滚,回滚half消息
// return LocalTransactionState.ROLLBACK_MESSAGE;
// 未知等待,下次继续
// return LocalTransactionState.UNKNOW;
// 成功
return LocalTransactionState.UNKNOW;
}
});
producer.start();
// 发送消息
Message message = new Message("myTrans001" ,"我是事务消息".getBytes());
producer.sendMessageInTransaction(message,null);
producer.shutdown();
System.out.println("结束");
}