天天看點

千萬日活的簽到系統如何設計?

作者:大資料與人工智能分享

1.什麼是分布式事務

什麼是分布式系統

部署在不同結點上的系統通過網絡互動來完成協同工作的系統比如:充值加積分的業務,使用者在充值系統向自己的賬戶充錢,在積分系統中自己積分相應的增加。充值系統和積分系統是兩個不同的系統,一次充值加積分的業務就需要這兩個系統協同工作來完成。

什麼是事務

事務是指由一組操作組成的一個工作單元,這個工作單元具有原子性(atomicity)、一緻性(consistency)、隔離性(isolation)和持久性(durability)。

  • 原子性:執行單元中的操作要麼全部執行成功,要麼全部失敗。如果有一部分成功一部分失敗那麼成功的操作要全部復原到執行前的狀态。
  • 一緻性:執行一次事務會使用資料從一個正确的狀态轉換到另一個正确的狀态,執行前後資料都是完整的。
  • 隔離性:在該事務執行的過程中,任何資料的改變隻存在于該事務之中,對外界沒有影響,事務與事務之間是完全的隔離的。隻有事務送出後其它事務才可以查詢到最新的資料。
  • 持久性:事務完成後對資料的改變會永久性的存儲起來,即使發生斷電當機資料依然在。

什麼是本地事務

本地事務就是用關系資料庫來控制事務,關系資料庫通常都具有ACID特性,傳統的單體應用通常會将資料全部存儲在一個資料庫中,會借助關系資料庫來完成事務控制。

什麼是分布式事務

在分布式系統中一次操作由多個系統協同完成,這種一次事務操作涉及多個系統通過網絡協同完成的過程稱為分布式事務。這裡強調的是多個系統通過網絡協同完成一個事務的過程,并不強調多個系統通路了不同的資料庫,即使多個系統通路的是同一個資料庫也是

千萬日活的簽到系統如何設計?

另外一種分布式事務的表現是,一個應用程式使用了多個資料源連接配接了不同的資料庫,當一次事務需要操作多個資料源,此時也屬于分布式事務,當系統作了資料庫拆分後會出現此種情況

千萬日活的簽到系統如何設計?

上面兩種分布式事務表現形式第一種用的最多

分布式事務的應用場景

千萬日活的簽到系統如何設計?

CAP理論

如何進行分布式事務控制?CAP理論是分布式事務處理的理論基礎,了解了CAP理論有助于我們研究分布式事務的處理方案。CAP理論是:分布式系統在設計時隻能在一緻性(Consistency)、可用性(Availability)、分區容忍性(Partition Tolerance)中滿足兩種,無法兼顧三種。通過下圖來了解CAP理論

千萬日活的簽到系統如何設計?
  • 一緻性(Consistency):服務A、B、C三個結點都存儲了使用者資料, 三個結點的資料需要保持同一時刻資料一緻性。
  • 可用性(Availability):服務A、B、C三個結點,其中一個結點當機不影響整個叢集對外提供服務,如果隻有服務A結點,當服務A當機整個系統将無法提供服務,增加服務B、C是為了保證系統的可用性。
  • 分區容忍性(Partition Tolerance):分區容忍性就是允許系統通過網絡協同工作,分區容忍性要解決由于網絡分區導緻資料的不完整及無法通路等問題。分布式系統不可避免的出現了多個系統通過網絡協同工作的場景,結點之間難免會出現網絡中斷、網延延遲等現象,這種現象一旦出現就導緻資料被分散在不同的結點上,這就是網絡分區

分布式系統能否兼顧C、A、P?

在保證分區容忍性的前提下一緻性和可用性無法兼顧,如果要提高系統的可用性就要增加多個結點,如果要保證資料的一緻性就要實作每個結點的資料一緻,結點越多可用性越好,但是資料一緻性越差。是以,在進行分布式系統設計時,同時滿足“一緻性”、“可用性”和“分區容忍性”三者是幾乎不可能的

CAP有哪些組合方式?

1、CA:放棄分區容忍性,加強一緻性和可用性,關系資料庫按照CA進行設計。2、AP:放棄一緻性,加強可用性和分區容忍性,追求最終一緻性,很多NoSQL資料庫按照AP進行設計。說明:這裡放棄一緻性是指放棄強一緻性,強一緻性就是寫入成功立刻要查詢出最新資料。追求最終一緻性是指允許暫時的資料不一緻,隻要最終在使用者接受的時間内資料 一緻即可3、CP:放棄可用性,加強一緻性和分區容忍性,一些強一緻性要求的系統按CP進行設計,比如跨行轉賬,一次轉賬請求要等待雙方銀行系統都完成整個事務才算完成。

  • 說明:由于網絡問題的存在CP系統可能會出現待等待逾時,如果沒有處理逾時問題則整理系統會出現阻塞
  • 總結:在分布式系統設計中AP的應用較多,即保證分區容忍性和可用性,犧牲資料的強一緻性(寫操作後立刻讀取到最新資料),保證資料最終一緻性。比如:訂單退款,今日退款成功,明日賬戶到賬,隻要在預定的使用者可以接受的時間内退款事務走完即可。

分布式事務的解決方案(介紹其中三種)

兩階段送出協定(2PC)

2PC兩階段送出協定應用于分布式事務場景,解決分布式多個系統間資料的一緻性問題。二階段送出(Two-phaseCommit)是指,為了使基于分布式系統架構下的所有節點在進行事務送出時保持資料一緻性而設計的一種算法(Algorithm)。通常,二階段送出也被稱為是一種協定(Protocol))。在分布式系統中,每個節點可以知道自己的操作的成功或失敗,卻無法知道其他節點的操作的成功或失敗。當一個事務跨越多個節點時,為了保持事務的ACID特性,需要引入一個作為協調者的元件來統一掌控所有節點(參與者)的操作結果并最終訓示,這些節點是否要把操作結果進行真正的送出(比如将更新後的資料寫入磁盤等等)。是以,二階段送出的算法思路可以概括為:參與者将操作的成功失敗通知協調者,再由協調者根據所有參與者的回報結果,決定各參與者是否要送出操作還是中止操作。

  • 所謂的兩個階段是指:第一階段:準備階段(投票階段)和第二階段:送出階段(執行階段)。

準備階段

事務協調者(事務管理器)給每個參與者(資料總管)發送Prepare消息,每個參與者要麼直接傳回失敗(如權限驗證失敗),要麼在本地執行事務,寫本地的redo和undo日志,但不送出,到達一種“萬事俱備,隻欠東風”的狀态。

可以進一步将準備階段分為以下三個步驟:

  • 1)協調者節點向所有參與者節點詢問是否可以執行送出操作(vote),并開始等待各參與者節點的響應。
  • 2)參與者節點執行詢問發起開始事務操作,并将Undo資訊和Redo資訊寫入日志。(注意:若成功這裡其實每個參與者已經執行了事務操作)
  • 3)各參與者節點響應協調者節點發起的詢問。如果參與者節點的事務操作實際執行成功,則它傳回一個”同意”消息;如果參與者節點的事務操作實際執行失敗,則它傳回一個”中止”消息。

送出階段

如果協調者收到了參與者的失敗消息或者逾時,直接給每個參與者發送復原(Rollback)消息;否則,發送送出(Commit)消息;參與者根據協調者的指令執行送出或者復原操作,釋放所有事務處理過程中使用的鎖資源。(注意:必須在最後階段釋放鎖資源)

接下來分兩種情況分别讨論送出階段的過程。當協調者節點從所有參與者節點獲得的相應消息都為”同意”時:

千萬日活的簽到系統如何設計?
  • 1)協調者節點向所有參與者節點發出”正式送出(commit)”的請求。
  • 2)參與者節點正式完成操作,并釋放在整個事務期間内占用的資源。
  • 3)參與者節點向協調者節點發送”完成”消息。
  • 4)協調者節點受到所有參與者節點回報的”完成”消息後,完成事務。

如果任一參與者節點在第一階段傳回的響應消息為”中止”,或者 協調者節點在第一階段的詢問逾時之前無法擷取所有參與者節點的響應消息時:

千萬日活的簽到系統如何設計?
  • 1)協調者節點向所有參與者節點發出”復原操作(rollback)”的請求。
  • 2)參與者節點利用之前寫入的Undo資訊執行復原,并釋放在整個事務期間内占用的資源。
  • 3)參與者節點向協調者節點發送”復原完成”消息。
  • 4)協調者節點受到所有參與者節點回報的”復原完成”消息後,取消事務。

不管最後結果如何,第二階段都會結束目前事務。

二階段送出看起來确實能夠提供原子性的操作,但是不幸的事,二階段送出還是有幾個缺點的:

  • 1、同步阻塞問題。執行過程中,所有參與節點都是事務阻塞型的。當參與者占有公共資源時,其他第三方節點通路公共資源不得不處于阻塞狀态。
  • 2、單點故障。由于協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤其在第二階段,協調者發生故障,那麼所有的參與者還都處于鎖定事務資源的狀态中,而無法繼續完成事務操作。(如果是協調者挂掉,可以重新選舉一個協調者,但是無法解決因為協調者當機導緻的參與者處于阻塞狀态的問題)
  • 3、資料不一緻。在二階段送出的階段二中,當協調者向參與者發送commit請求之後,發生了局部網絡異常或者在發送commit請求過程中協調者發生了故障,這會導緻隻有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務送出。于是整個分布式系統便出現了資料不一緻性的現象。
  • 4、二階段無法解決的問題:協調者再發出commit消息之後當機,而唯一接收到這條消息的參與者同時也當機了。那麼即使協調者通過選舉協定産生了新的協調者,這條事務的狀态也是不确定的,沒人知道事務是否被已經送出。由于二階段送出存在着諸如同步阻塞、單點問題、腦裂等缺陷,是以,研究者們在二階段送出的基礎上做了改進,提出了三階段送出。
  • 背景:假設有兩個系統A和B,同一個原子業務,舉個常用的轉賬例子,A系統加1000元,B系統相應減1000元,這時若A執行成功了,B執行失敗了,對業務來說肯定出問題了。這裡的問題出在系統A不知道B的狀态,B也不知道A。對于分布式系統,需要一個協調者來擷取每個系統的執行狀态。這個協調者可以由應用或資料庫/緩存的Agent來承擔都可以。

兩階段送出協定(2PC)

1)第一階段:準備階段(prepare)協調者通知參與者準備送出訂單,參與者開始投票。參與者完成準備工作向協調者回應Yes。2)第二階段:送出(commit)/復原(rollback)階段協調者根據參與者的投票結果發起最終的送出指令。如果有參與者沒有準備好則發起復原指令。一個下單減庫存的例子:

千萬日活的簽到系統如何設計?

1、應用程式連接配接兩個資料源。2、應用程式通過事務協調器向兩個庫發起prepare,兩個資料庫收到消息分别執行本地事務(記錄日志),但不送出,如果執行成功則回複yes,否則回複no。3、事務協調器收到回複,隻要有一方回複no則分别向參與者發起復原事務,參與者開始復原事務。4、事務協調器收到回複,全部回複yes,此時向參與者發起送出事務。如果參與者有一方送出事務失敗則由事務協調器發起復原事務。2PC的優點:實作強一緻性,部分關系資料庫支援(Oracle、MySQL等)。缺點:整個事務的執行需要由協調者在多個節點之間去協調,增加了事務的執行時間,性能低下。解決方案有:springboot+Atomikos or Bitronix

事務補償(TCC)

TCC事務補償是基于2PC實作的業務層事務控制方案,它是Try、Confirm和Cancel三個單詞的首字母,含義如下:1、Try 檢查及預留業務資源完成送出事務前的檢查,并預留好資源。2、Confirm 确定執行業務操作對try階段預留的資源正式執行。3、Cancel 取消執行業務操作對try階段預留的資源釋放。下邊用一個下單減庫存的業務為例來說明

千萬日活的簽到系統如何設計?
  • 1、Try下單業務由訂單服務和庫存服務協同完成,在try階段訂單服務和庫存服務完成檢查和預留資源。訂單服務檢查目前是否滿足送出訂單的條件(比如:目前存在未完成訂單的不允許送出新訂單)。庫存服務檢查目前是否有充足的庫存,并鎖定資源。
  • 2、Confirm訂單服務和庫存服務成功完成Try後開始正式執行資源操作。訂單服務向訂單寫一條訂單資訊。庫存服務減去庫存。
  • 3、Cancel如果訂單服務和庫存服務有一方出現失敗則全部取消操作。訂單服務需要删除新增的訂單資訊。庫存服務将減去的庫存再還原。優點:最終保證資料的一緻性,在業務層實作事務控制,靈活性好。缺點:開發成本高,每個事務操作每個參與者都需要實作try/confirm/cancel三個接口。注意:TCC的try/confirm/cancel接口都要實作幂等性,在為在try、confirm、cancel失敗後要不斷重試。

什麼是幂等性?

幂等性是指同一個操作無論請求多少次,其結果都相同。幂等操作實作方式有:1、操作之前在業務方法進行判斷如果執行過了就不再執行。2、緩存所有請求和處理的結果,已經處理的請求則直接傳回結果。3、在資料庫表中加一個狀态字段(未處理,已處理),資料操作時判斷未處理時再處理。

第二中方案:消息隊列實作最終一緻(本文打算介紹這種方案解決)

本方案是将分布式事務拆分成多個本地事務來完成,并且由消息隊列異步協調完成,如下圖:下邊以下單減少庫存為例來說明:

千萬日活的簽到系統如何設計?

1、訂單服務和庫存服務完成檢查和預留資源。2、訂單服務在本地事務中完成添加訂單表記錄和添加“減少庫存任務消息”。3、由定時任務根據消息表的記錄發送給MQ通知庫存服務執行減庫存操作。4、庫存服務執行減少庫存,并且記錄執行消息狀态(為避免重複執行消息,在執行減庫存之前查詢是否執行過此消息)。5、庫存服務向MQ發送完成減少庫存的消息。6、訂單服務接收到完成庫存減少的消息後删除原來添加的“減少庫存任務消息”。實作最終事務一緻要求:預留資源成功理論上要求正式執行成功,如果執行失敗會進行重試,要求業務執行方法實作幂等。優點 :由MQ按異步的方式協調完成事務,性能較高。不用實作try/confirm/cancel接口,開發成本比TCC低。缺點:此方式基于關系資料庫本地事務來實作,會出現頻繁讀寫資料庫記錄,浪費資料庫資源,另外對于高并發操作不是最佳方案。

總結:本文隻是介紹了分布式事務的一些特性和解決方案,将會在另一篇文章上詳細介紹消息隊列實作最終一緻性的分布式解決方案,需要了解:rabbitmq,SpringTask,springcloud

作者:奇點一氪連結:https://www.jianshu.com/p/50b6e907a100來源:簡書著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

繼續閱讀