事务消息本质上解决的问题是业务系统与消息系统之间的事务问题(跨系统分布式事务),其基本原理即两阶段提交以及最终一致性保障。最近看了下阿里云mns事务消息的实现原理,介绍的蛮简洁透彻的,对了解分布式事务实现原理挺有帮助,在阅读本文前推荐你们先仔细阅读下阿里云"mns事务消息"一文。php
事务消息
背景描述
有时候咱们须要实现本地操做和消息发送的事务一致性功能。即:消息发送成功,则本地操做成功;反之,若是消息发送失败,本地操做失败(成功也须要rollback)。保证不出现操做成功但消息发送失败;或者操做失败但消息发送成功的状况;
另外,消费端,咱们也但愿消息必定被成功处理一次,不会由于消息端程序崩溃而致使消息没有成功处理,进而须要人工重置消费进度。html解决方案
利用消息服务MNS的延迟消息功能来实现。mysql
准备工做
建立两个队列:
1.事务消息队列sql
消息的有效期小于消息延迟时间。即若是生产者不主动修改(提交)消息可见时间,消息对消费者不可见;2.操做日志队列网络
记录事务消息的操做记录信息。消息延迟时间为事务操做超时时间。日志队列中的消息确认(删除)后将对消费者不可见。<!-- more -->分布式
具体步骤
- 1.发送一条事务准备消息到事务消息队列;
- 2.写操做日志信息到操做日志队列,日志中包含步骤1消息的消息句柄;
- 3.执行本地事务操做;
- 4.若是步骤3成功,提交消息(消息对消费者可见);反之,回滚消息;
- 5.确认步骤2中的操做日志(删除该日志消息);
- 6.步骤4后,消费者能够接收到事务消息;
- 7.消费者处理消息;
- 8.消费者确认删除消息;
以下图:
异常分析:
生产者异常(例如:进程重启):
A.读取操做日志队列超时未确认日志
B.检查事务结果
C.若是检查获得事务已经成功,则提交消息(重复提交无反作用,同一句柄的消息只能成功提交一次)
D.确认操做日志阿里云消费者异常(例如:进程重启):
消息服务提供至少保证消费一次的特性,只要步骤8不成功,消息在一段时间后能够继续可见,被当前消费者或者其余消费者处理。spa
消息服务不可达(例如:断网)
消息发送和接收处理状态以及操做日志都在消息服务端,消息服务自己具有高可靠和高可用的特色,因此只要网络恢复,事务能够继续,能保证只要生产者:操做成功,则消费者必定可以拿到消息并处理成功;或操做失败, 则消费者收不到消息的最终一致性。.net
原文地址日志
这个过程须要注意到,咱们务必保证在preSendMessage没获得最终确认以前不被消费者获取到,所以须要将发送的lifetime小于delaytime。
看到这里也许你有疑问,为何要将过程切分红两阶段提交?咱们先假设若是采用一次提交的策略,很显然此次提交的切入点只能存在于①本地事务开始以前②本地事务中③本地事务结束以后,那么先看这三个切入点各自存在什么问题。
”单次提交“遇到的主要问题是:没法保障本地事务与消息被接受到的时序问题(或者说两个分布式事务的时序)以及数据的一致性问题。再回到”两阶段提交“,两阶段提交能解决这两个问题吗?两阶段提交的确认操做是在本地事务完成以后(这个相似于③),所以其可以解决时序问题,可是若是这个确认操做执行的过程当中发生了宕机等状况致使确认操做失败,依然会致使数据不一致问题。
mns经过延迟消息机制实现了两阶段提交,其如何保证数据一致性问题呢?通常咱们的策略都是经过操做流水来进行补偿以达到数据的最终一致性,一样的mns也是基于这个原理实现。
经过创建对opLog的监听,咱们可以确保事务的最终一致性吗?回答这个问题前,咱们先看这个问题的本质:最终、一致性。
最终一致性问题的产生是因为发生了一些不可预期的问题,致使一个事务被提交(回滚),但消息没被commit(rollback)。咱们经过opLog来追溯那些没有获得最终确认的消息并进行补偿(最终),而且经过检查本地事务的状态来确认此次补偿是commit或者是rollback(一致性)。正是基于这个补偿的策略,mns事务消息解决了"两阶段提交"所遗留的一致性问题,但这个过程当中咱们须要注意几个细节:
上面啰嗦的写了一堆,看到这咱们不妨对思考下mns事务消息解决的是业务系统(本地事务)与消息中间件之间的事务协同问题,若是是两个业务系统之间的分布式事务如何实现?
好吧,若是坚持看到这,你可能以为我标题党了...那么我建议你再读一下”mns事务消息“一文。
更多文章请访问个人博客转载请注明出处