原文链接在此,直通车:https://towardsdatascience.com/distributed-transactions-and-why-you-should-care-116b6da8d72
一篇讲解分布式事务的文章,有些地方译的有点生硬,没有润色
几乎译了一天,刚开始看的时候只关注共识机制,翻到一半发现,好像是在推广YugaByte,瞬间感觉到一股广告的怪味,但其中干货文章不少,可以直接点链接进去看。
下次可能会看看微软Azure的云服务
如果产品成功,最终一致性还会反过来困扰你吗?
任何人只要学过信息基础理论这门课,都听过ACID特性与CAP理论,但绝大多数人都认为,这些玩意只有搞分布式的工程师才需要了解。。。
毕竟我的数据库不应该保证在任何时间和地点都是可读写的吗?
你将成为介个孩子
为什么作为一个应用开发人员,我会关心如何让应用间的事务传播一致与分片后的数据原子性?
基于变换的数据模型,“数据库”的定义也一直在发生转换,ACID在这里不再被单纯的遵循。扩展的数据模型面对的是独有的挑战,没有完美的解决方案,各种妥协。。。数据量增长的冲击经常都落到写应用的程序员身上。
在一致性上有多种观点,最终一致性(eventual-consistency)的支持者认为不是所有应用都需要完全的ACID,放弃ACID能够提升响应速度,对于很多用例来说这是值得的。其他行业领导者与智囊团主张在数据层只推崇强一致性(strong-consistency),这能让应用开发者们写出可伸缩、无bug的代码,而不用让自己成为分布式系统专家,去考虑分布式事务。在MillWheel的论文中,谷歌主张数据层(Data Layer)必须具有强一致性,能够做到分布式ACID事务。
MillWheel is a framework for building low-latency data-processing applications that is widely used at Google. Users specify a directed computation graph and application code for individual nodes, and the system manages persistent state and the continuous flow of records, all within the envelope of the framework’s fault-tolerance guarantees.
为了让使用者只关注他们自己的应用业务逻辑,以下几种编程模型(programming model)能让使用者无需成为分布式系统专家就能推导出系统的语义。特别是,使用者能基于框架层面(framework-level)的正确性和容错性,把bug和错误通过公理化的推导,最大限度控制在表层。
为什么这是一个难题?第一个问题就是时间本身。。。很难让不同系统保持时间上的统一,物理时钟也无法让他们达成一致。。。时间上我们可以使用网络时间,但传输本身也需要时间。那么当节点无法对操作顺序达成共识时,怎么才能让执行计划一直有序的进行?此时,逻辑时钟在全局的有序事件中发挥了作用,但它通常跟物理时钟没有半毛线关系。
分布式数据模型(The Distributed Data Model)
当数据库横跨整个系统
你现在是独角兽,你审视着从全局发来的讯息。为了迎合日益增长的客户群体,你在其他区域扩展了你那超屌的NoSQL引擎,可能它们还横跨多个公有云(public-cloud)。此外,为了更快的读取到某一文档,你将数据库在不同集群间做了分区。你如何保证某一节点提交的事务传播到其他节点的原子性,在同一时间没有不一致的事务在其他节点上传播?在网络分区(network-partition)的情况下,对可用性和一致性如何取舍(节点失效或者心跳失败的时候)?
多阶段提交协议(Multi-phase commit protocols)和悲观读写锁(pessimistic read-write locking)能够确保分布式事务的一致性,但它在网络分区中用处并不大。
让我从乐观与悲观的角度考虑下一个简单应用的数据模型。
Earth-to-Echo旅游服务(这是一个例子)
这里有图
假设你的微服务应用是来给度蜜月和商务人员提供火星穿梭飞船订票服务。很显然,当比特币(Bitcoin)已经在地球和火星上流通时,你也可以通过比特币来进行订购支付。
乐观的数据模型
在乐观的数据模型中,应用异步请求触发更新消费和票务数据库,无需等待区块链(blockchain)或者票务服务的任何确认,就将事务标记为成功。
悲观的数据模型
悲观的数据模型产生一个阻塞的操作,它持有锁,直到足够数量的确认信息返回,如区块链有了回复,票务服务有了回复,才会将锁释放。如果其中一个操作失败,它将回滚事务(rolls-back)并补偿(refunded)已经完成的其他部分。
实际的模型介于乐观与悲观模型之间,事务在执行过程中,父事务会产生临时数据,同时,父事务中的嵌套子事务在并行运行,直到等待得到确认,整一事务才会继续运行。
原子性(Atomicity)
保证全通过或全失败(All or Nothing guarantees)
每次交易事件必须限定在一个单一同步的提交之中,数据库必须是正确的源头(或最尽可能接近真相)。为了分布式事务的原子性,当无法取得一致性时需要回滚,也就是不要将系统置于一个不一致的状态。
MVCC(Multi-Version Concurrency Control)
如何在读一条记录时,不用专门去写个持有锁的程序
MVCC是一个在数据库中根据不同时间戳版本保存同一操作的协议。这能让写无需持有锁,因为当他们一直读取的是最晚时间的快照。最通用的基于MVCC的隔离模型就是快照隔离模型(Snapshot Isolation Model)。
跨网络的时钟同步(Clock-synchronization across the network)
通过调解从原子时钟(Atomic Clocks)和GPS 系统获取的时间,数据库能够明显的减少全局同步时间(global synchronized clock)上的边界错误(the bounded error)。每个节点都有一个守护进程,校验与主节点之间全局时间的一致性。有个叫提交等待(Commit-Wait)的方法,用来确认多事务的提交只会有最少的边界错误。这个方法就是广为人知的事实时间-谷歌一个牛逼哄哄的点子。
另一个在分布式系统中通用的,实现全局时间戳一致的共识方法就是混合时间(Hybrid Time),同时结合了物理与逻辑时钟的优点。
混合时间(The Hybrid Time)算法无需为了修正时间而提交等待并且可以确定的是
事件遵循因果链,例如:“同一服务器中 A事件 先于 B事件 发生”,“A事件 在某一服务器中发生,然后通过RPC调用另一服务器,B事件 在另一服务器发生”,他们会一直根据增长的命令分配混合的时间戳。
一致性(Consistency)
所有节点在任一时间点做的同一操作看到的结果都一样
墨菲定律(Murphy Law:最终一致性陷阱)
基于最终一致性模型的分布式事务已经被取了个叫做微服务冰山的名字。根据作者所说,那些在他们系统中考虑使用便捷方式(the happy paths)的人,分布式事务一直未付诸实现,一天天过去系统一直很稳定,但当某一天小小的网络故障发生时,所有美景瞬间崩塌。
在最优解释中,最终一致性与时间线一致性(timeline-consistent)模型陷阱,卡西克(Karthik),YugaByte的CTO,Cassandra的原始作者之一,驱散了我们对可伸缩最终一致性模型的疑惑,同时对强一致性(或CP系统)会牺牲性能的困惑。
试想一个银行业的例子。我们知道Iron-Bank of Braavos从前是最富的银行。我们参考瑟曦(Cercei)和第谷(Tycho)的对话,在确认詹姆已经拿到黄金之前,Iron-Bank不会提高瑟曦的信用额度,不管瑟曦说金子已经在路上,即将偿还。
事实是,银行家们不希望产生一个弱一致性,弱一致性违反了ACID的某些属性。但这可能引致兰尼斯特(Lannisters)家族的垮台,铁王座之争也将迅速到达终点。
让我们设想下如果Iron-Bank使用的是弱一致性模型会发生什么。一部分可读写人员(Quorum Reads and Writes)在最终一致性模型中操作失败,两个分区中将会出现数据不一致的问题。
分布式系统一致性算法
共识是多节点保持结果一致所做的处理。在不可能出错的分布式共识操作(Impossibility of distributed consensus with one fault process)中,如作者所说,单点故障的情况下,没有一个异步协议可以在有限时间内一直保持一致。
两阶段提交(Two-Phase Commit Protocol):也许是使用最广的分布式共识算法,它包含两个阶段:投票阶段(The Voting Phase)和提交阶段(The Commit Phase)。在投票阶段,事务管理员询问所有节点,然后基于多数共识从而决定哪个是正确答案,再将正确答案分发给各个节点。如果所有节点都同意,事务管理员将联系所有参与者告知他们最终的结果。否则,将通知所有参与者终止同步。参与者无需对结果的一致性负责,但可以判断是否接受事务管理员提供的数值。
PAXOS:PAXOS是一种在网络中存在不可信节点中达成共识的方法。它包含以下几个角色,客户(Client)在分布式系统中发起一次请求,接收人(Acceptor)这是一个一定数目的群体,申请人(Proposer)发起客户端请求,说服接收人接受自己,学习人(Learner)既是一个卓越的申请人也是一个卓越的学习人。领导人(Leader)选择“有效数据”并将它发送给所有节点,节点会回复接受或者拒收。如果大部分节点接收,那么值将被提交。阿帕奇动物管理员(Apache Zookeeper)和谷歌扳手(Google Spanner)都使用了PAXOS算法来达到共识的目的。
RAFT:RAFT共识算法在保证效率和性能方面之外跟PAXOS很像。它分为三个角色,领导、随从,候选人(leader、followers、candidates)。领导的选举发生在心跳或任意事故下的超时之后。领导从客户端接收日志集合,同时通过集群再次传播它们。YugaByte使用RAFT达成共识,并在线添加、移除或修改集群中的节点。当集群中有足够的节点促成选举,YugaByte同样能对集群中的少数分区做到容错。
PBFT实用拜占庭容错(Practical Byzantine Fault Tolerance)
PBFT是一个能解决拜占庭将军问题的共识算法。拜占庭将军问题发生在系统错误或绝大部分参与者可信的情况下。例如:拜占庭将军问题可能发生在某一参与者未响应,或参与者故意发送错误信息,或返回给不同系统截然不同的结果。
POW工作量证明(Proof Of Work)
在POW类型算法中,任意一个矿工想挖取下一个区块,都需要耗费大量的计算资源。区块将被获取并添加区块链中。大多数会加入最长链中。挖矿最困难的是控制一直改变的区块产生率。比特币(Bitcoin)和以太坊(Ethereum)与数不胜数的数字货币需要通过POW达成共识。这是一个1个CPU一票(1-cpu-1-vote)的模型,攻击者能够通过超过51%的算力从而控制整个网络。
POS权益证明(Proof Of Stake)
更多的权益意味着候选人更有机会挖到下一个区块。POS是基于BFT的链。Neo和Cardano是在网络中使用POS达成共识的两种数字货币。也有提案说通过Casper工具升级,来让以太坊迁移至POS。
隔离性(Isolation)
每个事务执行都好像全局只有它一个在执行一样
- 快照隔离
- 序列化隔离
持久化(Durability)
所有状态的变更都需要在提交后保持一致
扩展阅读
- 分布式计算的谬论:http://nighthacks.com/jag/res/Fallacies.html
- 分布式事务-ACID和BASE理论:https://www.cs.rutgers.edu/~pxk/417/notes/content/transactions.html
- 分布式数据库中的隔离级别:https://docs.yugabyte.com/latest/architecture/transactions/isolation-levels/
- 临时记录的事务IO:https://docs.yugabyte.com/latest/architecture/transactions/transactional-io-path/
- 简述一个不可能的FLP过程(one fault process):http://www.the-paper-trail.org/post/2008-08-13-a-brief-tour-of-flp-impossibility/
- 在分布式系统中执行事件的时间、时钟和顺序:https://lamport.azurewebsites.net/pubs/time-clocks.pdf
- 蜜蜂民主——在给予同样有利可图的选择时,演员的行为:https://www.worldcat.org/title/honeybee-democracy/oclc/587249075
后边的不译了