-
传统发送消息模式:先执行本地事务,成功之后,后发送消息给第三方,
问题1.发送消息失败:第三方就没有收到消息,例如发送消息失败了(异常情况:mq宕机,网络异常),但是本地事务又成功了,就需要人工处理了。人工重发消息等 -
传统发送消息的模式存在的问题是,无论你先发送消息再执行事务,还是先执行事务再发送消息,都存在问题。
1.先发送消息,然后再执行事务,如果中间出现异常,事务执行失败,则出现了不一致
2.先执行事务,再发送消息,如果中间出现异常,消息发送失败,也会导致不一致,
-
因此:我们需要一个凭证,让我们知道,在发生异常之后,去补偿处理另一个阶段的操作,而这个凭证就可以用rocketmq的事务消息的半消息来提供,这样就可以大大降低异常的概率
-
传统发送消息有mq宕机,网络异常的情况,而事务消息有一个两阶段确认的这一操作,可以大大降低这种丢失的概率
采用事务消息:
1.先发送半消息,确保消息发送是没有问题的,如果发送半消息失败,则直接删除该半消息,就是设置一个删除标志
2.成功发送半消息后,然后执行本地事务(producer的executeLocalTransaction),判断执行结果:
2.1 如果本地事务执行成功:则提交事务消息,消费者可以正常消费
2.2 如果本地事务执行失败:则直接删除该半消息
2.3 如果本地事务执行状态未知:则不处理该消息
3.TransactionalMessageCheckService线程,默认一分钟扫描一次未处理的半消息,
如果该半消息没有超过最大检测次数(默认15次)且没有超过过期时间(默认72小时),则回查一次本地的事务状态,否则直接丢弃
调用TransactionListener的checkLocalTransaction方法,判断本地事务状态:
3.1 如果本地事务执行成功:则提交事务消息,消费者可以正常消费
3.2 如果本地事务执行失败:则直接删除该半消息
3.3 如果本地事务执行状态未知:则不处理该消息
事务消息的优点:
①:消息的投递失败时(比如MQ宕机或者网络丢失),Producer是可以感知到的,因为最终的业务提交是在回调的execute方法里面执行的
②:如果消息成功发送到Broker,但是没有Producer最终Commit Ack时(比如Producer宕机了),该事务消息仍然处于预提交的状态,不会被消费者读取到,这保证了消息在P和C端的状态一致性
参考:
https://www.jianshu.com/p/cc5c10221aa1
https://www.cnblogs.com/jelly12345/p/14351697.html
https://zhuanlan.zhihu.com/p/183753774
https://blog.csdn.net/prestigeding/article/details/81318980