- begin transaction:update User set account = account - 100 where userId = 'A'
- insert into message(userId, amount, status) values('A', 100, 1)
- commit transaction
然后经由过程pull或者push模式,大年夜营业获撤消息并履行。如不雅是push模式,那么一般运器具有持久化功能的消息队列,大年夜事务务订阅消息。如不雅是pull模式,那么大年夜事务准时去拉撤消息,然后履行。
mongodb的写入就很像本地消息表,在WriteConcern为w:1的情况下,更新操作只要写到oplog以及primary就可以向客户端返回。secondary异步拉取oplog并本地记录履行。
事务消息:
事务消息依附于支撑“事务消息”的消息队列,其根本思惟是 应用消息中心间实施两阶段提交,将本地事务和发消息放在了一个分布式事务里,包管要么本地操作成功成功并且对外发消息成功,要么两者都掉败。流程如下:
- 主事务向消息队列发送预告消息主事务收到ACK之后本地履行主事务
- 根据履行的结不雅(成功或掉败)向消息队列发送提交或者回滚消息
具体的流程如下图(图片来源见水印)所示:
不难看到,比拟本地消息表的方法,事务消息由消息中心件包管本地事务与消息的原子性,不依附于本地数据库存储消息。但实现了“事务消息”的消息队列比较少,还不敷通用。
不管是本地消息表照样事务消息,都须要包管大年夜事务履行且仅仅履行一次,exact once。如不雅掉败,须要重试,但也弗成能无穷次的重试,昔时夜事务最终掉败的情况下,须要通知主营业回滚吗?然则此时,主事务已经提交,是以只能经由过程补偿,实现逻辑上的回滚,而当前时光点距主事务的提交已经有一准时光,回滚也可能掉败。是以,最好是包管大年夜事务逻辑上不会掉败,万一掉败,记录log并报警,人工介入。
1PC
1PC(one phase commit)这个概念,我是在《Distributed systems for fun and profit》一文中看到的,应当是对标2PC,3PC。在wiki中并没有正式的词条,在google汕9依υ?┞仿也不是很多。在我的懂得中,1PC实用于分布式存储体系的复制集,即复制集中多个节点的数据提交,。一般来说,这些节点存储同样的数据,只要单个节点能提交,其他节点理论上也应当可以提交。 在《Distributed systems for fun and profit》中是这么描述的:
- Having a second phase in place before the commit is considered permanent is useful, because it allows the system to roll back an update when a node fails. In contrast, in primary/backup (“1PC”), there is no step for rolling back an operation that has failed on some nodes and succeeded on others, and hence the replicas could diverge.
即对于分布式存储中应用异常广泛的中间化复制集协定Primary Secondary,在朝分节点掉败、部分节获成功的情况下没有回滚操作,可能会导致不一致。不过这些分布式存储体系都竭力包管,这些不一致是临时的,会经由过程重试等手段包管最终的一致。
1PC的长处是机能异常好,并且只有在出现物理故障的时刻才会出现不一致。
比如在MongoDB中,更新操作会写入Primary节点以及oplog collection,Secondary节点大年夜Primary节点的oplog collection拉取操作日记并履行,这是一个异步的过程。及时Secondary节点因为故障履行oplog掉败,Promary节点的数据也不会回滚。在《带着问题进修分布式体系之中间化复制集》中也提到过,为了进步数据靠得住性(避免极端情况下数据被回滚),设定WriteConcern为w:Majority,(shard有一个Primary 一个Secondary 一个Arbiter构成)。如不雅这个时刻因为个一一个secondary挂掉落,写入操作是弗成能成功的。是以,在超不时光达到之后,会向客户端返回掉足信息。然则在这个时刻数据是持久化到了primary节点,不会被回滚。如不雅此时Secondary重启,那么是会大年夜Primary拉取日记并履行。所以当客户端返回的掉足信息包含WriteResult.writeConcernError 时,应当谨慎处理
思虑这个问题的初志,是有一次给同伙转账,结不雅我的钱被扣了,同伙充公到钱。而我之前一向认为银行转账必定是由事务包管强一致性的,于是进修、总结了一下分布式事务的各类理论、办法。
对于分布式文件体系GFS、haystack,如不雅Secondary节点掉败,也会采取简单粗暴的重试,并经由过程一些机制(cheksum,offset)来包管最终能读到精确的数据
思虑与总结
原子性这个器械,即使不是分布式,仅仅是单过程单线程也是须要推敲的,这就是C++中的RAII,python中的with statement,以及各类说话的try…finally…。当涉及到跨过程、异步通信的时刻,就很难经由过程说话层面的机制包管原子性了。
推荐阅读
沙龙晃荡 | 去哪儿、陌陌、ThoughtWorks在主动化运维中的实践!10.28不见不散! 这篇文┞仿只须要你10分钟的时光。什么是Zookeeper?固然zookeeper的实现比较复杂,然则它供给的模型抽象倒是>>>详细阅读
本文标题:从银行转账失败到分布式事务:总结与思考
地址:http://www.17bianji.com/lsqh/38129.html
1/2 1