日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

從銀行轉(zhuǎn)賬失敗到分布式事務(wù):總結(jié)與思考

 xujin3 2017-12-16

思考這個(gè)問(wèn)題的初衷,是有一次給朋友轉(zhuǎn)賬,結(jié)果我的錢被扣了,朋友沒收到錢。而我之前一直認(rèn)為銀行轉(zhuǎn)賬一定是由事務(wù)保證強(qiáng)一致性的,于是學(xué)習(xí)、總結(jié)了一下分布式事務(wù)的各種理論、方法。


事務(wù)是一個(gè)非常廣義的詞匯,各行各業(yè)解讀都不一樣。對(duì)于程序員,事務(wù)等價(jià)于Transaction,是指一組連續(xù)的操作,這些操作組合成一個(gè)邏輯的、完整的操作。即這組操作執(zhí)行前后,系統(tǒng)需要處于一個(gè)可預(yù)知的、一致的狀態(tài)。因此,這一組操作要么都成功執(zhí)行,要么都不能執(zhí)行;如果部分成功,部分失敗,成功的部分需要回滾(rollback)。


姊妹篇:再論分布式事務(wù):從理論到實(shí)踐(http://www.cnblogs.com/xybaby/p/7756163.html


關(guān)系型數(shù)據(jù)庫(kù)事務(wù)


大多數(shù)人可能和我一樣,第一次聽說(shuō)事務(wù)是在學(xué)習(xí)關(guān)系型數(shù)據(jù)庫(kù)(mysql、sql server、Oracle)的時(shí)候,在關(guān)系型數(shù)據(jù)庫(kù)中,如果一組操作滿足ACID特性,那么稱之為一個(gè)事務(wù)。關(guān)于關(guān)系型數(shù)據(jù)庫(kù)的ACID特性,不管是教材還是網(wǎng)絡(luò)上都有大量的資料,這里只簡(jiǎn)單介紹。


  • A(Atomic):原子性,構(gòu)成事務(wù)的所有操作,要么都執(zhí)行完成,要么全部不執(zhí)行,不可能出現(xiàn)部分成功部分失敗的情況

  • C(Consistency):一致性,在事務(wù)執(zhí)行前后,數(shù)據(jù)庫(kù)的一致性約束沒有被破壞。這里的一致性含義后面會(huì)詳細(xì)解釋

  • I(Isolation):隔離性,數(shù)據(jù)庫(kù)中的事務(wù)一般都是并發(fā)的,隔離性是指并發(fā)的兩個(gè)事務(wù)的執(zhí)行互不干擾,一個(gè)事務(wù)不能看到其他事務(wù)運(yùn)行過(guò)程的中間狀態(tài)

  • D(Durability):持久性,事務(wù)完成之后,該事務(wù)對(duì)數(shù)據(jù)的更改會(huì)被持久化到數(shù)據(jù)庫(kù),且不會(huì)被回滾。


我們舉一個(gè)簡(jiǎn)單的轉(zhuǎn)賬的例子,用戶A給玩家B轉(zhuǎn)100塊錢,那么涉及到兩個(gè)操作:玩家A的賬戶扣100元,玩家B的賬戶加100元。即


UserA.account -= 100
UserB.account += 100


原子性很好理解,這兩個(gè)操作要么都成功,要么都不執(zhí)行(更準(zhǔn)確的是從效果上來(lái)看等價(jià)于都沒有執(zhí)行)。不可能出現(xiàn)用戶A的錢減少了而用戶B的錢沒增加的情況,用戶是不允許的;更不可能出現(xiàn)用戶B的錢增加 而 用戶A的錢沒有減少的情況,銀行是絕對(duì)不干的。


一致性說(shuō)一起來(lái)大家都懂,但是深究起來(lái)也是似懂非懂。ACID中的一致性,網(wǎng)絡(luò)上的介紹都很模糊,都是說(shuō)要處于一致的狀態(tài),那什么是一致的狀態(tài)呢,比如轉(zhuǎn)賬操作中,A扣錢,B加錢,AB的錢的綜合是一定的,這個(gè)是否屬于ACID中的Consistency呢?我覺得不是的,Wiki Transaction_processing(https://en./wiki/Transaction_processing和Wiki: ACID(https://en./wiki/ACID)分別是這么描述的:


 Consistency: A transaction is a correct transformation of the state. The actions taken as a group do not violate any of the integrity constraints associated with the state.


The consistency property ensures that any transaction will bring the database from one valid state to another. Any data written to the database must be valid according to all defined rules, including constraints, cascades, triggers, and any combination thereof. This does not guarantee correctness of the transaction in all ways the application programmer might have wanted (that is the responsibility of application-level code), but merely that any programming errors cannot result in the violation of any defined rules.


上面黑色加粗的部分指出,ACID中的一致性是指完整性約束不被破壞,完整性包含實(shí)體完整性(主屬性不為空)、參照完整性(外鍵必須存在原表中)、用戶自定義的完整性。用戶自定義的完整性比如列值非空(not null)、列值唯一(unique)、列值是否滿足一個(gè)bool表達(dá)式(check語(yǔ)句,如性別只能有兩個(gè)值、歲數(shù)是一定范圍內(nèi)的整數(shù)等),例如age smallint CHECK (age >=0 AND age <= 120).數(shù)據(jù)庫(kù)保證age的值在[0,="" 120]的范圍,如果不在這個(gè)范文,那么更新操作失敗,事務(wù)也會(huì)失敗。另外,向mysql中的cascade,以及觸發(fā)器(trigger)都屬于用戶自定義的完整性約束。在mongodb3.2中document="" validation="">http://www.cnblogs.com/xybaby/p/%20https://docs./manual/core/document-validation/)就是用戶自定義的完整性約束,在插入或者更新docuemnt的時(shí)候檢查,不過(guò)用戶可以自行設(shè)定validationAction,確定當(dāng)數(shù)據(jù)不符合約束時(shí)的表現(xiàn),默認(rèn)為error,即拒絕數(shù)據(jù)寫操作。


因此,用戶A,B在這次事務(wù)操作前后,賬戶的總和一定,是應(yīng)用層面的一致性,而不是數(shù)據(jù)庫(kù)保證的一致性,應(yīng)用層面的一致性事實(shí)上是由原子性來(lái)保證的。


隔離性說(shuō)起來(lái)簡(jiǎn)單,但事實(shí)上背后的事情很復(fù)雜,數(shù)據(jù)庫(kù)的隔離性依賴于加鎖或者多版本控制。簡(jiǎn)單來(lái)說(shuō),如果UserA.account初始值為500,執(zhí)行完第一條指令(即減去100),但事務(wù)還沒有提交,其他的事務(wù)是不能讀到這個(gè)中間結(jié)果(UserA.account的值為400)的。這就是避免了臟讀(Drity Read),對(duì)應(yīng)的隔離級(jí)別就是READ_COMMITTED。在SQL標(biāo)準(zhǔn)中,定義了四個(gè)隔離級(jí)別:


  READ_UNCOMMITTED
  READ_COMMITTED
  REPEATABLE_READ
  SERIALIZABLE


來(lái)解決事務(wù)并發(fā)中帶來(lái)的一下幾個(gè)問(wèn)題臟讀(Dirty Read)、不可重復(fù)讀(Non-repeatable Read)、幻讀(Phantom Read)


不同的數(shù)據(jù)庫(kù)或者說(shuō)存儲(chǔ)引擎默認(rèn)支持不同的隔離級(jí)別,比如InnoDB存儲(chǔ)引擎默認(rèn)支持REPEATABLE_READ,而Mongodb只支持READ_UNCOMMITTED

 

持久性需要考慮到一個(gè)事務(wù)在執(zhí)行過(guò)程中的各種情況的異常。一個(gè)事務(wù)的流程是這樣的:


開啟一個(gè)事務(wù)
執(zhí)行一組操作
如果都執(zhí)行成功,那么提交并結(jié)束事務(wù)
如果任何操作失敗,那么回滾已經(jīng)執(zhí)行的操作,結(jié)束事務(wù)


在事務(wù)執(zhí)行過(guò)程中,如果出現(xiàn)故障,比如斷電、宕機(jī),這個(gè)時(shí)候就要利用日志(redo log或者undo log) 加上 checkpoint來(lái)保證事務(wù)的完整結(jié)束。


分布式事務(wù)


當(dāng)數(shù)據(jù)的規(guī)模越來(lái)越大,超出了單個(gè)關(guān)系型數(shù)據(jù)庫(kù)的處理能力,這個(gè)時(shí)候就出現(xiàn)了關(guān)系型數(shù)據(jù)的垂直分表或者水平分表,也出現(xiàn)了天然支持水平擴(kuò)展(sharding)的NoSql。另外,大型網(wǎng)站的服務(wù)化(SOA)以及這兩年非?;鸬奈⒎?wù),往往將服務(wù)進(jìn)行拆分,單獨(dú)部署,自然也使用獨(dú)立的數(shù)據(jù)庫(kù),甚至是異構(gòu)的數(shù)據(jù)庫(kù)。這個(gè)時(shí)候,關(guān)系型數(shù)據(jù)庫(kù)保證事務(wù)的手段,比如加鎖、日志就行不通了。當(dāng)然,本文討論的不僅僅是數(shù)據(jù)庫(kù),也包含分布式存儲(chǔ)、消息隊(duì)列,以及任何要保證原子性、持久性的邏輯。


分布式事務(wù)的最大挑戰(zhàn)在于CAP,在《CAP理論與MongoDB一致性、可用性的一些思考》(http://www.cnblogs.com/xybaby/p/6871764.html)一文中有詳細(xì)介紹。簡(jiǎn)而言之,由于網(wǎng)絡(luò)分割(P: Network Partition)的存在,用戶不得不在一致性(C Consistency)與可用性(A: Avaliable)之前做權(quán)衡。如果要保證強(qiáng)一致性(主要是應(yīng)用層面的強(qiáng)一致性),那么在網(wǎng)絡(luò)分割的時(shí)候,系統(tǒng)就不可用;如果要保證高可用性,那么就只能提供弱一致性,保證最終一致。下面提到的各種實(shí)現(xiàn)分布式事務(wù)的方法、協(xié)議都需要在一致性與可用性之間權(quán)衡。


2PC


提到分布式事務(wù),首先想到的肯定是兩階段提交(2pc, two-phase commit protocol),2pc是非常經(jīng)典的強(qiáng)一致性、中心化的原子提交協(xié)議。中心化是指協(xié)議中有兩類節(jié)點(diǎn):一個(gè)中心化協(xié)調(diào)者節(jié)點(diǎn)(coordinator)和N個(gè)參與者節(jié)點(diǎn)(participant、cohort)。


顧名思義,兩階段提交協(xié)議的每一次事務(wù)提交分為兩個(gè)階段:


在第一階段,協(xié)調(diào)者詢問(wèn)所有的參與者是否可以提交事務(wù)(請(qǐng)參與者投票),所有參與者向協(xié)調(diào)者投票。


在第二階段,協(xié)調(diào)者根據(jù)所有參與者的投票結(jié)果做出是否事務(wù)可以全局提交的決定,并通知所有的參與者執(zhí)行該決定。在一個(gè)兩階段提交流程中,參與者不能改變自己的投票結(jié)果。兩階段提交協(xié)議的可以全局提交的前提是所有的參與者都同意提交事務(wù),只要有一個(gè)參與者投票選擇放棄(abort)事務(wù),則事務(wù)必須被放棄。 


wiki上給出了簡(jiǎn)要流程:



注意,上圖中最下面一行也表明,兩階段提交協(xié)議也依賴與日志,只要存儲(chǔ)介質(zhì)不出問(wèn)題,兩階段協(xié)議就能最終達(dá)到一致的狀態(tài)(成功或者回滾)


而下圖(來(lái)自slideshare:https://www./sourabhdave/distributed-databases-24839617)詳細(xì)描述了整個(gè)流程:

在劉杰的《分布式原理介紹中》,有非常詳細(xì)的流程介紹,可以配合上圖一起看,另外還介紹了在各種異常情況下(比如Coordinator、Participant宕機(jī),網(wǎng)絡(luò)分割導(dǎo)致的超時(shí))兩階段協(xié)議的工作情況、工作效率。另外,在這篇文章(http://blog./95632/)中也有比較清晰的流程介紹。在這里只討論2PC的優(yōu)缺點(diǎn):


  • 優(yōu)點(diǎn):強(qiáng)一致性,只要節(jié)點(diǎn)或者網(wǎng)絡(luò)最終恢復(fù)正常,協(xié)議就能保證順利結(jié)束;部分關(guān)系型數(shù)據(jù)庫(kù)(Oracle)、框架直接支持

  • 缺點(diǎn):兩階段提交協(xié)議的容錯(cuò)能力較差,比如在節(jié)點(diǎn)宕機(jī)或者超時(shí)的情況下,無(wú)法確定流程的狀態(tài),只能不斷重試;兩階段提交協(xié)議的性能較差, 消息交互多,且受最慢節(jié)點(diǎn)影響


這篇文章(http://www.cnblogs.com/xybaby/p/%20http://blog.csdn.net/m0_38031406/article/details/76474800)描述了為什么兩階段提交協(xié)議在分布式系統(tǒng)中不適用:


系統(tǒng)“水平”伸縮的死敵?;趦呻A段提交的分布式事務(wù)在提交事務(wù)時(shí)需要在多個(gè)節(jié)點(diǎn)之間進(jìn)行協(xié)調(diào),最大限度地推后了提交事務(wù)的時(shí)間點(diǎn),客觀上延長(zhǎng)了事務(wù)的執(zhí)行時(shí)間,這會(huì)導(dǎo)致事務(wù)在訪問(wèn)共享資源時(shí)發(fā)生沖突和死鎖的概率增高,隨著數(shù)據(jù)庫(kù)節(jié)點(diǎn)的增多,這種趨勢(shì)會(huì)越來(lái)越嚴(yán)重,從而成為系統(tǒng)在數(shù)據(jù)庫(kù)層面上水平伸縮的'枷鎖', 這是很多Sharding系統(tǒng)不采用分布式事務(wù)的主要原因。


所言甚是!


3PC


三階段提交協(xié)議(3pc Three-phase_commit_protocol)主要是為了解決兩階段提交協(xié)議的阻塞問(wèn)題,從原來(lái)的兩個(gè)階段擴(kuò)展為三個(gè)階段,并且增加了超時(shí)機(jī)制。


3PC只是解決了在異常情況下2PC的阻塞問(wèn)題,但導(dǎo)致一次提交要傳遞6條消息,延時(shí)很大。具體流程描述可參見《關(guān)于分布式事務(wù)、兩階段提交協(xié)議、三階提交協(xié)議 》(https://en./wiki/ACID)一文。


TCC


TCC是Try、Commit、Cancel的縮寫,在國(guó)內(nèi)由于支付寶的布道(http://www.sohu.com/a/124709543_468650%20)而廣為人知,TCC在保證強(qiáng)一致性的同時(shí),最大限度提高系統(tǒng)的可伸縮性與可用性


我們假設(shè)一個(gè)完整的業(yè)務(wù)包含一組子業(yè)務(wù),Try操作完成所有的子業(yè)務(wù)檢查,預(yù)留必要的業(yè)務(wù)資源,實(shí)現(xiàn)與其他事務(wù)的隔離;Confirm使用Try階段預(yù)留的業(yè)務(wù)資源真正執(zhí)行業(yè)務(wù),而且Confirm操作滿足冪等性,以遍支持重試;Cancel操作釋放Try階段預(yù)留的業(yè)務(wù)資源,同樣也滿足冪等性。“一次完整的交易由一系列微交易的Try 操作組成,如果所有的Try 操作都成功,最終由微交易框架來(lái)統(tǒng)一Confirm,否則統(tǒng)一Cancel,從而實(shí)現(xiàn)了類似經(jīng)典兩階段提交協(xié)議(2PC)的強(qiáng)一致性?!?/span>


與2PC協(xié)議比較 ,TCC擁有以下特點(diǎn):


位于業(yè)務(wù)服務(wù)層而非資源層 ,由業(yè)務(wù)層保證原子性

沒有單獨(dú)的準(zhǔn)備(Prepare)階段,降低了提交協(xié)議的成本

Try操作 兼?zhèn)滟Y源操作與準(zhǔn)備能力 

Try操作可以靈活選擇業(yè)務(wù)資源的鎖定粒度,而不是鎖住整個(gè)資源,提高了并發(fā)度


當(dāng)然,TCC需要較高的開發(fā)成本,每個(gè)子業(yè)務(wù)都需要有響應(yīng)的comfirm、Cancel操作,即實(shí)現(xiàn)相應(yīng)的補(bǔ)償邏輯。


基于消息的分布式事務(wù)


這類事務(wù)機(jī)制將分布式事務(wù)分成多個(gè)本地事務(wù),這里稱之為主事務(wù)與從事務(wù)。首先主事務(wù)本地先行提交,然后通過(guò)消息通知從事務(wù),從事務(wù)從消息中獲取信息進(jìn)行本地提交??梢钥闯鲞@是一種異步事務(wù)機(jī)制、只能保證最終一致性;但可用性非常高,不會(huì)因?yàn)楣收隙l(fā)生阻塞。另外,主事務(wù)已經(jīng)先行提交,如果因?yàn)閺氖聞?wù)無(wú)法提交,要回滾主事務(wù)還是比較麻煩,所以這種模式只適用于理論上大概率等成功的業(yè)務(wù)情況,即從事務(wù)的提交失敗可能是由于故障,而不大可能是邏輯錯(cuò)誤。


基于異步消息的事務(wù)機(jī)制主要有兩種方式:本地消息表與事務(wù)消息。二者的區(qū)別在于:怎么保證主事務(wù)的提交與消息發(fā)送這兩個(gè)操作的原子性。


如果用異步消息實(shí)現(xiàn)轉(zhuǎn)賬的例子,那么操作分為四部:用戶A扣錢,發(fā)消息,用戶B收消息,用戶B扣錢。前兩步必須保證原子性,如果A扣錢成功但是沒有發(fā)出消息,那么用戶A損失了;如果發(fā)消息成功,但是沒有扣錢,那么用戶B就多得了一筆錢,銀行肯定不干。


本地消息表


基于本地消息表的方案是指將消息寫入本地?cái)?shù)據(jù)庫(kù),通過(guò)本地事務(wù)保證主事務(wù)與消息寫入的原子性。例如銀行轉(zhuǎn)賬的例子,偽碼(http://blog.csdn.net/gaowenhui2008/article/details/53910341)如下:


 begin transaction:

  update User set account = account - 100 where userId = 'A'
  insert into message(userId, amount, status) values('A', 100, 1)

commit transaction


然后通過(guò)pull或者push模式,從業(yè)務(wù)獲取消息并執(zhí)行。如果是push模式,那么一般使用具有持久化功能的消息隊(duì)列,從事務(wù)務(wù)訂閱消息。如果是pull模式,那么從事務(wù)定時(shí)去拉取消息,然后執(zhí)行。


MongoDB的寫入就很像本地消息表,在WriteConcern為w:1的情況下,更新操作只要寫到oplog以及primary就可以向客戶端返回。secondary異步拉取oplog并本地記錄執(zhí)行。


事務(wù)消息


事務(wù)消息依賴于支持“事務(wù)消息”的消息隊(duì)列,其基本思想是 利用消息中間間實(shí)施兩階段提交,將本地事務(wù)和發(fā)消息放在了一個(gè)分布式事務(wù)里,保證要么本地操作成功成功并且對(duì)外發(fā)消息成功,要么兩者都失敗。流程如下:

    

主事務(wù)向消息隊(duì)列發(fā)送預(yù)備消息

主事務(wù)收到ACK之后本地執(zhí)行主事務(wù)

根據(jù)執(zhí)行的結(jié)果(成功或失?。┫蛳㈥?duì)列發(fā)送提交或者回滾消息


詳細(xì)的流程如下圖(圖片來(lái)源見水?。篽ttp://blog.csdn.net/mine_song/article/details/64118963)所示:


  


不難看到,相比本地消息表的方式,事務(wù)消息由消息中間件保證本地事務(wù)與消息的原子性,不依賴于本地?cái)?shù)據(jù)庫(kù)存儲(chǔ)消息。但實(shí)現(xiàn)了“事務(wù)消息”的消息隊(duì)列比較少,還不夠通用。

 

不管是本地消息表還是事務(wù)消息,都需要保證從事務(wù)執(zhí)行且僅僅執(zhí)行一次,exact once。如果失敗,需要重試,但也不可能無(wú)限次的重試,當(dāng)從事務(wù)最終失敗的情況下,需要通知主業(yè)務(wù)回滾嗎?但是此時(shí),主事務(wù)已經(jīng)提交,因此只能通過(guò)補(bǔ)償,實(shí)現(xiàn)邏輯上的回滾,而當(dāng)前時(shí)間點(diǎn)距主事務(wù)的提交已經(jīng)有一定時(shí)間,回滾也可能失敗。因此,最好是保證從事務(wù)邏輯上不會(huì)失敗,萬(wàn)一失敗,記錄log并報(bào)警,人工介入。


1PC


1PC(one phase commit)這個(gè)概念,我是在《Distributed systems for fun and profit》(http://book./distsys/)一文中看到的,應(yīng)該是對(duì)標(biāo)2PC,3PC。在wiki中并沒有正式的詞條,在google上的文章也不是很多。在我的理解中,1PC適用于分布式存儲(chǔ)系統(tǒng)的復(fù)制集,即復(fù)制集中多個(gè)節(jié)點(diǎn)的數(shù)據(jù)提交,。一般來(lái)說(shuō),這些節(jié)點(diǎn)存儲(chǔ)同樣的數(shù)據(jù),只要單個(gè)節(jié)點(diǎn)能提交,其他節(jié)點(diǎn)理論上也應(yīng)該可以提交。 在《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.


即對(duì)于分布式存儲(chǔ)中使用非常廣泛的中心化復(fù)制集協(xié)議Primary Secondary,在部分節(jié)點(diǎn)失敗、部分節(jié)點(diǎn)成功的情況下沒有回滾操作,可能會(huì)導(dǎo)致不一致。不過(guò)這些分布式存儲(chǔ)系統(tǒng)都竭力保證,這些不一致是暫時(shí)的,會(huì)通過(guò)重試等手段保證最終的一致。


1PC的優(yōu)點(diǎn)是性能非常好,而且只有在出現(xiàn)物理故障的時(shí)候才會(huì)出現(xiàn)不一致。


比如在MongoDB中,更新操作會(huì)寫入Primary節(jié)點(diǎn)以及oplog collection,Secondary節(jié)點(diǎn)從Primary節(jié)點(diǎn)的oplog collection拉取操作日志并執(zhí)行,這是一個(gè)異步的過(guò)程。及時(shí)Secondary節(jié)點(diǎn)因?yàn)楣收蠄?zhí)行oplog失敗,Promary節(jié)點(diǎn)的數(shù)據(jù)也不會(huì)回滾。在《帶著問(wèn)題學(xué)習(xí)分布式系統(tǒng)之中心化復(fù)制集》(http://www.cnblogs.com/xybaby/p/7153755.html)中也提到過(guò),為了提高數(shù)據(jù)可靠性(避免極端情況下數(shù)據(jù)被回滾),設(shè)定WriteConcern為w:Majority,(shard有一個(gè)Primary 一個(gè)Secondary 一個(gè)Arbiter組成)。如果這個(gè)時(shí)候由于其中一個(gè)secondary掛掉,寫入操作是不可能成功的。因此,在超時(shí)時(shí)間到達(dá)之后,會(huì)向客戶端返回出錯(cuò)信息。但是在這個(gè)時(shí)候數(shù)據(jù)是持久化到了primary節(jié)點(diǎn),不會(huì)被回滾。如果此時(shí)Secondary重啟,那么是會(huì)從Primary拉取日志并執(zhí)行。所以當(dāng)客戶端返回的出錯(cuò)信息包含WriteResult.writeConcernError (https://docs./manual/reference/method/WriteResult/#WriteResult.writeConcernError)時(shí),應(yīng)該謹(jǐn)慎處理


對(duì)于分布式文件系統(tǒng)GFS、haystack,如果Secondary節(jié)點(diǎn)失敗,也會(huì)采取簡(jiǎn)單粗暴的重試,并通過(guò)一些機(jī)制(cheksum,offset)來(lái)保證最終能讀到正確的數(shù)據(jù)


思考與總結(jié)


更多的時(shí)候,分布式事務(wù)只需要保證原子性,這個(gè)原子性也保證了應(yīng)用層面上的一致性,而由本地事務(wù)來(lái)保證隔離性、持久性。


原子性這個(gè)東西,即使不是分布式,僅僅是單進(jìn)程單線程也是需要考慮的,這就是C++中的RAII,python中的with statement,以及各種語(yǔ)言的try...finally...。當(dāng)涉及到跨進(jìn)程、異步通信的時(shí)候,就很難通過(guò)語(yǔ)言層面的機(jī)制保證原子性了。


在分布式領(lǐng)域,由于網(wǎng)絡(luò)或者機(jī)器故障,經(jīng)常需要重試,因此冪等性非常重要


很多場(chǎng)景,比如電商、網(wǎng)絡(luò)購(gòu)票,首先要保證的是高可用,不大可能采用強(qiáng)一致性,因此我們也會(huì)看到‘正在處理中...‘這種中間狀態(tài),后臺(tái)很可能是異步處理的,在12306買過(guò)票的話都知道,下單成功到最后是否能出票由很長(zhǎng)一段時(shí)間。


在筆者的業(yè)務(wù)領(lǐng)域,并沒有涉及到強(qiáng)一致性的場(chǎng)景,只要最終一致性就行了。上面的提到的各種辦法,不管是2PC、TCC、本地消息表、事務(wù)消息,都需要引入額外的框架或者組件。所以更多的時(shí)候是采取業(yè)務(wù)補(bǔ)償?shù)姆绞剑热缫粋€(gè)涉及兩個(gè)進(jìn)程的操作需要保證原子性,進(jìn)程間RPC通信,那么一般是A進(jìn)程先執(zhí)行,然后RPC調(diào)用B進(jìn)程接口,根據(jù)B進(jìn)程的返回結(jié)果,絕對(duì)是否回滾(補(bǔ)償);但如果涉及到異步RPC、或者多線程、或者兩個(gè)以上進(jìn)程的串聯(lián)時(shí),那么就不一定能補(bǔ)償、甚至很難補(bǔ)償了,這個(gè)時(shí)候只記錄一個(gè)error log,然后通知人工排查。因此,事務(wù)補(bǔ)償只適合業(yè)務(wù)比較簡(jiǎn)單的常見,而且很難形成通用的框架,或者說(shuō)實(shí)用性不強(qiáng)。


之前一直以為像銀行轉(zhuǎn)賬這種場(chǎng)景,一定是強(qiáng)一致性的。后來(lái)自己遇到這么一回事,我給朋友轉(zhuǎn)賬,我這邊顯示轉(zhuǎn)賬成功,但朋友并沒有收到錢。我以為是需要一定時(shí)間,結(jié)果24小時(shí)之后還沒有收到。我自己重新比對(duì)轉(zhuǎn)賬單,才發(fā)現(xiàn)是把對(duì)方的開戶銀行寫錯(cuò)了。因此可見,轉(zhuǎn)賬這個(gè)操作肯定不是強(qiáng)一致性,具體怎么搞的在網(wǎng)上也沒有查到。更坑爹的是,轉(zhuǎn)賬失敗,我的錢被扣了,朋友也沒有收到錢,但是我沒有收到任何消息,也沒有給我把錢退回來(lái),在我打電話到銀行去咨詢之后才退回來(lái)。這個(gè)體驗(yàn)真的很差,但銀行是大爺,沒辦法!


References


  • Wiki Transaction_processing:https://en./wiki/Transaction_processing

  • Wiki: ACID:https://en./wiki/ACID

  • Wiki: two-phase commit protocol:https://en./wiki/Two-phase_commit_protocol

  • 關(guān)于分布式事務(wù)、兩階段提交協(xié)議、三階提交協(xié)議:https://en./wiki/ACID

  • 劉杰:分布式原理介紹

  • Distributed systems for fun and profit:http://book./distsys/


出處:http://www.cnblogs.com/xybaby/p/7465816.html


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多