分布式事務實現-Spanner


  Spanner要滿足的external consistency是指:后開始的事務一定可以看到先提交的事務的修改。所有事務的讀寫都加鎖可以解決這個問題,缺點是性能較差。特別是對於一些workload中只讀事務占比較大的系統來說不可接受。為了讓只讀事務不加任何鎖,需要引入多版本。在單機系統中,維護一個遞增的時間戳作為版本號很好辦。分布式系統中,機器和機器之間的時鍾有誤差,並且誤差范圍不確定,帶來的問題就是很難判斷事件發生的前后關系。反應在Spanner中,就是很難給事務賦予一個時間戳作為版本號,以滿足external consistency。在這樣一個誤差范圍不確定的分布式系統時,通常,獲得兩個事件發生的先后關系主要通過在節點之間進行通信分析其中的因果關系(casual relationship),經典算法包括Lamport時鍾等算法。然而,Spanner采用不同的思路,通過在數據中心配備原子鍾和GPS接收器來解決這個誤差范圍不確定的問題,進而解決分布式事務時序這個問題。基於此,Spanner提供了TrueTime API,返回值實際為一個區間[t-ε,t+ε],ε為時間誤差,毫秒級,保證當前的真實時間位於這個區間。

  Spanner是一個支持分布式讀寫事務,只讀事務的分布式存儲系統,只讀事務不加任何鎖。和其他分布式存儲系統一樣,通過維護多副本來提高系統的可用性。一份數據的多個副本組成一個paxos group,通過paxos協議維護副本之間的一致性。對於涉及到跨機的分布式事務,涉及到的每個paxos group中都會選出一個leader,來參與分布式事務的協調。這些個leader又會選出一個大leader,稱為coordinator leader,作為兩階段提交的coordinator,記作coordinator leader。其他leader作為participant。

  數據庫事務系統的核心挑戰之一是並發控制協議。Spanner的讀寫事務使用兩階段鎖來處理。詳細流程下圖所示。

  如第一段所述,給事務賦予一個時間戳版本號是這樣一個分布式存儲系統的核心。下面先說如何確定讀寫事務的版本號,再說只讀事務。

  前面已經說了兩階段提交過程中兩階段鎖的過程,這里就省略這些,只討論兩階段提交過程中如何確定最后的讀寫事務的時間戳版本號。

  讀寫事務

 

 

 

 

 

 

簡要時序圖如下:

  

 

圖中,commit wait分為兩段,第一階段是論文中4.1.2節提到的Start,第二階段是4.1.2節的Commit Wait 

只讀事務

   調用TrueTime API,將右區間作為只讀事務的版本號,記作Sread, 如果讀事務涉及到的副本不夠新,那么讀會阻塞。每個副本會維護一個時間戳Tsafe, 如果Sread <= Tsafe ,則這個副本夠新。Tsafe取兩個時間戳的更小值,第一個是副本所在的paxos group中已經apply到狀態機的時間戳,第二個是paxos group中leader目前正在參與的還沒有commit的分布式事務在該paxos group的最小的prepared timestamp - 1。

   還有一種方法,可以不用客戶端等,方法是Sread通過客戶端和所有涉及到的paxos group的leader進行協商,每個leader返回他們的最后一次事務的commit時間戳給客戶端,然后客戶端取最小的版本號作為Sread即可。

下面說一下兩階段提交的錯誤處理。

  兩階段提交協議由於協調者和參與者的故障可能會有嚴重的可用性問題。Spanner的兩階段提交實現基於Paxos協議,每個participant和coordinator本身產生的日志都會通過paxos協議復制到自身的paxos group中,從而解決可用性問題。同樣以A,B,C三份數據為例,他們分別有三個副本,記作(A1,A2,A3),(B1,B2,B3),(C1,C2,C3),每組作為一個paxos group,內部通過paxos協議保證一致性。假設,A1,B1,C1分別為各自paxos group的leader,A1為coordinator leader。

  Prepare階段:A1給B1和C1發送prepare消息后,假設B1掛了,A1等待超時,A1給C1發送rollback。B1后續回滾分為兩種情況:1. B1在持久化prepare消息之前掛了,B1恢復后可自行回滾 2. 如果B1持久化prepare消息之后掛了,B1自身可以回放日志得知事務未決,主動聯系(A1,A2,A3)。A1給B1,C1發送prepare消息之后,自己掛了,同樣,A1通過回放日志可以得知。實際上,A1本身掛了之后,A2和A3通過選主協議馬上會選出一個新的leader,不至於影響到可用性。

   Commit階段:A1給B1,C1發送commit消息,B1 commit成功,C1掛了,C1起來后,如果C1之前沒有持久化commit消息,則A1主動要求C1繼續commit。如果C1之前已經持久化了commit消息,則自己commit。如果C1由於某些原因,始終commit不成功,則由上層業務進行回補操作。

 

參考資料

Spanner: Google’s Globally-Distributed Database

presentation:Spanner: Google’s Globally-Distributed Database


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM