1、儘可能在業務上和技術上避免分佈式事務算法
顯而易見,微服務架構十分的流行,特別是對於電商領域來講。他的優勢就很少說了,可是隨着集羣機器的增長,集羣的規模也愈來愈大,隨着集羣搭載的服務規模也愈來愈大,致使事務的處理也就愈來愈複雜,有可能一個事務涉及到n多個服務,可想而知就算再優良的方案也很難處理這麼複雜的事務,與其硬着頭皮犧牲性能和可靠性,還不如改變業務,再結合技術對事務進行分割,將複雜的事務簡單化,將簡單的事務消化化。數據庫
2、兩段式提交(2PC),XA/JTA已經實現了編程
在分佈式系統中,每一個節點雖然能夠知曉本身的操做是成功或者失敗,卻沒法知道其餘節點的操做的成功或失敗。當一個事務跨越多個節點時,爲了保持事務的ACID特性,須要引入一個做爲協調者的組件來統一掌控全部節點(參與者)的操做結果並最終指示這些節點是否須要把操做結果進行真正的提交。算法步驟以下:微信
第一階段:架構
一、協調者會問全部的參與者,是否能夠執行提交操做。併發
二、各個參與者開始事務執行的準備工做,如:爲資源上鎖,預留資源。框架
三、參與者響應協調者,若是事務的準備工做成功,則迴應「能夠提交」,不然迴應「拒絕提交」。異步
第二階段:分佈式
一、若是全部的參與者都回應「能夠提交」。那麼協調者向全部的參與者發送「正式提交」的命令。參與者完成正式提交併釋放全部資源,而後迴應「完成」,協調者收集各節點的「完成」迴應後結束這個Global Transaction微服務
二、若是有一個參與者迴應「拒絕提交」,那麼協調者向全部的參與者發送「回滾操做」,並釋放全部資源,而後迴應「回滾完成」,協調者收集各節點的「回滾」迴應後,取消這個Global Transaction。
咱們能夠看到,2PC說白了就是第一階段作Vote,第二階段作決定的一個算法,也能夠看到2PC這個事是強一致性的算法。2PC用的是比較多的,在一些系統設計中,會串聯一系列的調用,好比:A -> B -> C -> D,每一步都會分配一些資源或改寫一些數據。好比咱們B2C網上購物的下單操做在後臺會有一系列的流程須要作。若是咱們一步一步地作,就會出現這樣的問題,若是某一步作不下去了,那麼前面每一次所分配的資源須要作反向操做把他們都回收掉,因此,操做起來比較複雜。如今不少處理流程(Workflow)都會借鑑2PC這個算法,使用 try -> confirm的流程來確保整個流程的可以成功完成。? ?另外,咱們也能夠看到其中的一些問題,
A)其中一個是同步阻塞操做,這個事情必然會很是大地影響性能。?
B)另外一個主要的問題是在TimeOut上,好比,
1)若是第一階段中,參與者沒有收到詢問請求,或是參與者的迴應沒有到達協調者。那麼,須要協調者作超時處理,一旦超時,能夠看成失敗,也能夠重試。
2)若是第二階段中,正式提交發出後,若是有的參與者沒有收到,或是參與者提交/回滾後的確認信息沒有返回,一旦參與者的迴應超時,要麼重試,要麼把那個參與者標記爲問題結點剔除整個集羣,這樣能夠保證服務結點都是數據一致性的。
3)糟糕的狀況是,第二階段中,若是參與者收不到協調者的commit/fallback指令,參與者將處於「狀態未知」階段,參與者徹底不知道要怎麼辦,好比:若是全部的參與者完成第一階段的回覆後(可能所有yes,可能所有no,可能部分yes部分no),若是協調者在這個時候掛掉了。那麼全部的結點徹底不知道怎麼辦(問別的參與者都不行)。爲了一致性,要麼死等協調者,要麼重發第一階段的yes/no命令。
兩段提交最大的問題就是第3)項,若是第一階段完成後,參與者在第二階沒有收到決策,那麼數據結點會進入「不知所措」的狀態,這個狀態會block住整個事務。也就是說,協調者Coordinator對於事務的完成很是重要,Coordinator的可用性是個關鍵。 因些,咱們有了三段提交。
3、三段式(3PC)提交(三段式提交實現起來很是的複雜,因此不多被使用)
三段提交的核心理念是:在詢問的時候並不鎖定資源,除非全部人都贊成了,纔開始鎖資源。他把二段提交的第一個段break成了兩段:詢問,而後再鎖資源。最後真正提交。
4、Paxos算法
Paxos 算法解決的問題是在一個可能發生上述異常的分佈式系統中如何就某個值達成一致,保證不論發生以上任何異常, 都不會破壞決議的一致性。一個典型的場景是,在一個分佈式數據庫系統中,若是各節點的初始狀態一致,每一個節點都執行相同的操做序列,那麼他們最後能獲得一個一致的狀態。爲保證每一個節點執行相同的命令序列,須要在每一條指令上執行一個「一致性算法」以保證每一個節點看到的指令一致。一個通用的一致性算法能夠應用在許多場景中,是分佈式計算中的重要問題。從20世紀80年代起對於一致性算法的研究就沒有中止過。
簡單說來,Paxos的目的是讓整個集羣的結點對某個值的變動達成一致。Paxos算法基本上來講是個民主選舉的算法——大多數的決定會成個整個集羣的統一決定。任何一個點均可以提出要修改某個數據的提案,是否經過這個提案取決於這個集羣中是否有超過半數的結點贊成(因此Paxos算法須要集羣中的結點是單數)
這個算法有兩個階段(假設這個有三個結點:A,B,C):
第一階段:Prepare階段
A把申請修改的請求Prepare Request發給全部的結點A,B,C。注意,Paxos算法會有一個Sequence Number(你能夠認爲是一個提案號,這個數不斷遞增,並且是惟一的,也就是說A和B不可能有相同的提案號),這個提案號會和修改請求一同發出,任何結點在「Prepare階段」時都會拒絕其值小於當前提案號的請求。因此,結點A在向全部結點申請修改請求的時候,須要帶一個提案號,越新的提案,這個提案號就越是 ? ? ? 最大的。若是接收結點收到的提案號n大於其它結點發過來的提案號,這個結點會迴應Yes(本結點上最新的被批准提案號),並保證不接收其它<n的提案。這樣一來,結點上在Prepare階段里老是會對最新的提案作承諾。
優化:在上述 prepare 過程當中,若是任何一個結點發現存在一個更高編號的提案,則須要通知 提案人,提醒其中斷此次提案。
第二階段:Accept階段
若是提案者A收到了超過半數的結點返回的Yes,而後他就會向全部的結點發布Accept Request(一樣,須要帶上提 案號n),若是沒有超過半數的話,那就返回失敗。
當結點們收到了Accept Request後,若是對於接收的結點來講,n是最大的了,那麼,它就會修改這個值,若是發現本身有一個更大的提案號,那麼,結點就會拒絕修改。
咱們能夠看以,這彷佛就是一個「兩段提交」的優化。其實,2PC/3PC都是分佈式一致性算法的殘次版本,Google Chubby的做者Mike Burrows說過這個世界上只有一種一致性算法,那就是Paxos,其它的算法都是殘次品。
5、補償性的TCC類型
所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分爲三塊:Try、Confirm和Cancel三個操做。以在線下單爲例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,若是更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是經過代碼人爲實現了兩階段提交,不一樣的業務場景所寫的代碼都不同,複雜度也不同,所以,這種模式並不能很好地被複用。
6、消息事務+最終一致性(異步確保型)
所謂的消息事務就是基於消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,它是將本地事務和發消息放在了一個分佈式事務裏,保證要麼本地操做成功成功而且對外發消息成功,要麼二者都失敗,開源的RocketMQ就支持這一特性,具體原理以下:
一、A系統向消息中間件發送一條預備消息
二、消息中間件保存預備消息並返回成功
三、A執行本地事務
四、A發送提交消息給消息中間件
經過以上4步完成了一個消息事務。對於以上的4個步驟,每一個步驟均可能產生錯誤,下面一一分析:
步驟一出錯,則整個事務失敗,不會執行A的本地操做
步驟二出錯,則整個事務失敗,不會執行A的本地操做
步驟三出錯,這時候須要回滾預備消息,怎麼回滾?答案是A系統實現一個消息中間件的回調接口,消息中間件會去不斷執行回調接口,檢查A事務執行是否執行成功,若是失敗則回滾預備消息
步驟四出錯,這時候A的本地事務是成功的,那麼消息中間件要回滾A嗎?答案是不須要,其實經過回調接口,消息中間件可以檢查到A 執行成功了,這時候其實不須要A發提交消息了,消息中間件能夠本身對消息進行提交,從而完成整個消息事務
基於消息中間件的兩階段提交每每用在高併發場景下,將一個分佈式事務拆成一個消息事務(A系統的本地操做+發消息)+B系統的本地操做,其中B系統的操做由消息驅動,只要消息事務成功,那麼A操做必定成功,消息也必定發出來了,這時候B會收到消息去執行本地操做,若是本地操做失敗,消息會重投,直到B操做成功,這樣就變相地實現了A與B的分佈式事務。原理以下:
雖然上面的方案可以完成A和B的操做,可是A和B並非嚴格一致的,而是最終一致的,咱們在這裏犧牲了一致性,換來了性能的大幅度提高。固然,這種玩法也是有風險的,若是B一直執行不成功,那麼一致性會被破壞,具體要不要玩,仍是得看業務可以承擔多少風險。
7、最大努力通知型
按規律進行通知,不保證數據必定能通知成功,但會提供可查詢操做接口進行覈對。這種方案主要用在與第三方系統通信時,好比:調用微信或支付寶支付後的支付結果通知。這種方案也是結合MQ進行實現,例如:經過MQ發送http請求,設置最大通知次數。達到通知次數後即再也不通知。