1. 首页
  2. > 代理记账 >

银行卡开户银行弄错(银行卡卡号对的开户行填错了怎么办)




3PC只是解决了在异常情况下2PC的阻塞问题,但导致一次提交要传递6条消息,延时很大。具体流程描述可参见《关于分布式事务、两阶段提交协议、三阶提交协议 》一文。


不难看到,相比本地消息表的方式,事务消息由消息中间件保证本地事务与消息的原子性,不依赖于本地数据库存储消息。但实现了“事务消息”的消息队列比较少,还不够通用。


不管是本地消息表还是事务消息,都需要保证从事务执行且仅仅执行一次,exact once。如果失败,需要重试,但也不可能无限次的重试,当从事务最终失败的情况下,需要通知主业务回滚吗?但是此时,主事务已经提交,因此只能通过补偿,实现逻辑上的回滚,而当前时间点距主事务的提交已经有一定时间,回滚也可能失败。因此,最好是保证从事务逻辑上不会失败,万一失败,记录log并报警,人工介入。



1PC

1PC(one phase commit)这个概念,我是在《Distributed systems for fun and profit》一文中看到的,应该是对标2PC,3PC。在wiki中并没有正式的词条,在google上的文章也不是很多。在我的理解中,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 backan operation that has failed on some nodes and succeeded on others, and hence the replicas could perge.


即对于分布式存储中使用非常广泛的中心化复制集协议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...。当涉及到跨进程、异步通信的时候,就很难通过语言层面的机制保证原子性了。


在分布式领域,由于网络或者机器故障,经常需要重试,因此幂等性非常重要


很多场景,比如电商、网络购票,首先要保证的是高可用,不大可能采用强一致性,因此我们也会看到‘正在处理中...‘这种中间状态,后台很可能是异步处理的,在12306买过票的话都知道,下单成功到最后是否能出票由很长一段时间。


在笔者的业务领域,并没有涉及到强一致性的场景,只要最终一致性就行了。上面的提到的各种办法,不管是2PC、TCC、本地消息表、事务消息,都需要引入额外的框架或者组件。所以更多的时候是采取业务补偿的方式,比如一个涉及两个进程的操作需要保证原子性,进程间RPC通信,那么一般是A进程先执行,然后RPC调用B进程接口,根据B进程的返回结果,绝对是否回滚(补偿);但如果涉及到异步RPC、或者多线程、或者两个以上进程的串联时,那么就不一定能补偿、甚至很难补偿了,这个时候只记录一个error log,然后通知人工排查。因此,事务补偿只适合业务比较简单的常见,而且很难形成通用的框架,或者说实用性不强。


之前一直以为像银行转账这种场景,一定是强一致性的。后来自己遇到这么一回事,我给朋友转账,我这边显示转账成功,但朋友并没有收到钱。我以为是需要一定时间,结果24小时之后还没有收到。我自己重新比对转账单,才发现是把对方的开户银行写错了。因此可见,转账这个操作肯定不是强一致性,具体怎么搞的在网上也没有查到。更坑爹的是,转账失败,我的钱被扣了,朋友也没有收到钱,但是我没有收到任何消息,也没有给我把钱退回来,在我打电话到银行去咨询之后才退回来。这个体验真的很差,但银行是大爷,没办法!


参考文献


Wiki Transaction_processing


Wiki:ACID


Wiki:two-phase commit protocol


关于分布式事务、两阶段提交协议、三阶提交协议


刘杰:分布式原理介绍


Distributed systems for fun and profit


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至123456@qq.com 举报,一经查实,本站将立刻删除。

联系我们

工作日:9:30-18:30,节假日休息