分佈式理論基礎



點擊上方 疾風先生能夠訂閱哦

在這一篇中主要講述分佈式基礎理論知識,其中包含CAP定理,ACID以,BASE理論以及一致性協議分析.有了CAP定理的基礎,可以幫助咱們在根據業務特色進行分區容錯一致性模型設計中提供解決問題的方向以及架構設計方案的設計與落地實現.同時須要區分數據庫ACID的AC與咱們的分佈式AC存在的聯繫與差別,其次,在分佈式網絡中,爲避免節點故障抑或是網絡延遲等問題致使系統服務出現大量的不可用問題,那麼對於BASE理論實現的技術方案有哪些.最後講述分佈式系統中數據的一致性問題.
java




CAP定理python

網絡分區容錯(Partition tolerance)
  • 網絡連通性
服務節點之間的網絡通訊正常

在上述能夠看到,服務A集羣與冗餘服務A1與A2節點造成一個對外閉環的集羣,同理服務B也構成一個閉環集羣.此時發起一個請求操做,須要經過服務A與服務B進行協做,在服務B節點正常運做狀況下,這個時候的分佈式網絡是處於連通狀態,服務A與服務B之間可以進行正常網絡通訊完成數據協做.nginx

  • 網絡分區web

服務節點之間的網絡通訊發生中斷或者是延遲響應出現短期的中斷.

在上述的圖中,一個請求操做須要經過服務節點A與服務節點B完成協做,可是若是服務B沒有作集羣部署,此時服務節點B發生故障或者是網絡延遲,那麼這個時候服務節點A與服務節點B之間將沒法進行通訊,此時服務A將與服務B失去聯繫,即服務節點之間發生網絡通訊中斷而產生網絡分區,此時服務A節點與服務B節點被劃分爲彼此獨立互不相連的節點服務,即以下:

  • 分區容錯算法

服務節點之間的網絡通訊可以經過容錯處理手段來保證服務節點之間互通.

爲了保證上述的服務A與服務B可以正常通訊,即便服務B節點發生故障,也能夠經過集羣服務B的其餘節點B1或者是B2來繼續爲服務A提供服務,以保證服務A節點可以正常完成請求操做的處理.而對於這種狀況稱爲分區容錯,在分佈式環境中,節點故障與網絡延遲是沒法避免的,所以爲了保證咱們的分佈式系統服務可以正常運做,那麼在進行架構設計的時候就須要作到知足CAP定理中的分區容錯(Partition Tolerance)數據庫

一致性(Consistency)
客戶端每次發起的讀取請求,不管是訪問分佈式集羣中的哪一個節點,都可以讀取到最新的一份寫入數據.
分佈式一致性的理解以下:

在上述發起一個事務操做請求的時候,集羣的服務A接收事務請求操做v=v1的處理,此時服務A須要並未將數據同步到冗餘服務節點A1以及A2,而這個時候向集羣A服務發起讀取請求操做,因爲集羣服務的負載均衡分配算法會將讀取請求轉發到服務A1,可是此時存儲數據v的服務節點A1並未從服務A同步到最新的數據v,此時客戶端讀取到數據v並不是是最新寫入的數據,致使讀取數據結果不一致.這個時候爲了保證數據的一致性,就須要要求服務節點A在接收到數據狀態變動的同時也須要向集羣服務中的冗餘服務節點發起數據同步操做,保證其餘冗餘服務節點與服務節點A最新寫入的數據是一致的.也就是說分佈式系統的一致性須要保證在有狀態的服務節點下數據的讀取是最新寫入的,即:後端

而對於數據在分佈式環境進行同步操做的時候,會存在如下兩個核心問題:
  • 節點發生故障如何保證讀取的數據是一致性的,即存在節點故障問題
  • 節點之間須要經過網絡進行數據同步,即存在網絡延遲問題
可用性(Availability)
要實現可用性,須要犧牲數據的一致性,也就是沒法保證數據看到都是最新的一份.

咱們先來思考分佈式系統中哪些地方會存在不可用的狀況:api

  • 單節點故障致使服務的不可用.微信

  • 服務與服務之間調用依賴,被調用方服務發生故障,調用方服務也會發生故障致使不可用.網絡

  • 當發起一個事務請求操做經過服務A來調用服務B的時候,此時服務節點B須要同步數據到其餘冗餘服務節點B1以及B2,若是此時有讀取請求的操做來訪問服務節點A,爲了保證看到的數據是最新的,這個時候因爲B1或者B2節點未完成數據同步可是要保證數據讀取最新這個時候會致使服務A出現短暫的不可用,或者稱爲同步等待數據返回.

經過上述咱們看到,節點故障咱們能夠經過分區容錯解決,也就說在分佈式系統設計中分區容錯與可用性是能夠並存的,而服務調用方發生故障致使不可用,也能夠認爲是分區容錯的一種手段,只不過是在應用層次經過過載保護或者是降級進行控制;然而對於後者,咱們看到要保證數據的一致性,讀取請求須要進行同步等待服務節點完成數據的同步操做以後再進行返回,那麼在這個等待的時間窗口內,對於客戶端而言,讀取請求資源的操做出現短期內的不可用.

由此可知,在咱們的分佈式環境下,爲了保證節點與節點之間的正常通訊,即保證分佈式系統服務節點的網絡連通性,咱們必需要知足分區容錯這一特性,而C與A只能知足其一.但對於RDBMS系統而言,好比MySQL或者是Oracle的關係型數據庫,這類傳統的關係型數據庫因爲設計的初衷都不是考慮分佈式系統設計,而是保證一致性以及系統可用,尤爲是事務操做的一致性,讀寫實時性抑或是複雜SQL的多表查詢,放到分佈式系統中實現要更爲複雜.因而纔有了分佈式數據庫,好比MongoDB知足CP原則,而CouchDB知足AP原則.同時對於關係型數據庫,好比MySQL,咱們會經過冗餘服務複製來知足分佈式系統設計的AP抑或是經過CP + AP的方式實現分庫分表的集羣.

CAP定理應用以下圖所示:

所以,當咱們在思考分佈式系統設計的時候,須要基於CAP定理從業務數據層面去思考咱們的架構設計方案.




ACID理論

事務的ACID
  • 原子性(Atomicity)

是指一個數據庫操做的事務不可分割的工做單位,要麼操做成功,要麼操做失敗.

  • 一致性(Consistency)

一致性是指事務開啓以前以及開啓以後數據庫的完整性約束沒有被破壞.

  • 隔離性(Isolation)

多個事務併發訪問的時候,兩個事務之間彼此相互獨立而且互不影響,一個事務不該該影響其餘事務運行效果.

  • 持久化(Durability)

意味着在事務完成之後,該事務對數據庫所做的更改便持久的保存在數據庫之中,並不會被回滾

  • 分佈式系統如何保證事務的ACID

當咱們瞭解到一個操做具有ACID特性的時候,咱們基本上能夠認爲完成了一個事務操做,而在分佈式系統中,實現一個知足ACID的請求操做須要考慮到網絡以及節點故障問題等問題,因而就須要經過分佈式事務協議來保證完成一個具有ACID特性的請求操做.

2PC事務協議
  • 工做原理

分爲投票階段以及提交階段,集羣服務節點扮演角色有協調者(Coordinator)以及事務的參與者(Cohort).

其工做流程以下:

投票階段

首先向集羣服務節點發起一個事務請求操做,即v=v1,這個時候集羣服務選舉一個協調者來負責接收事務請求的操做,並由協調者統一指揮相應的事務操做.這個時候接收到事務請求以後協調者將向集羣服務各個參與事務的節點發起v=v1操做請求,詢問是否容許進行操做.

這個時候服務集羣參與者的節點接收到協調者的操做請求,並在執行當前的操做請求的時候進行undo以及redo的日誌記錄,經過undo日誌實現回滾,redo日誌實現持久化,最後將響應結果返回給協調者.

提交階段 - 成功提交

協調者接收到參與者節點進行事務執行操做準備的響應,根據參與者節點的響應結果,爲了保證事務的ACID特性,若是全部的參與者節點都容許進行事務v=v1的請求操做時,那麼這個時候協調者就會向各個參與者節點服務發起commit的請求並等待各個參與者節點事務操做結果的響應.

參與者接收到協調者的提交請求以後,這個時候每一個參與者節點就能夠正常完成單點機器的事務操做,即知足事務ACID的特性,完成事務操做以後每一個參與者節點都會向協調者發起事務操做結果的響應.這個時候協調者接收到事務操做響應的結果並向客戶端給予事務操做成功的響應.

提交階段 - 失敗提交

  • 參與者3因網絡緣由致使超時未響應

  • 參與者3拒絕v=v1的請求操做

對於實現分佈式事務的ACID,要保證數據的強一致性,所以只要其中有一個參與者節點在進行事務投票階段發生上述問題,這個時候協調者會視爲abort,則協調者下一步將會發起abort的回滾操做,即:

協調者根據參與者節點給予的響應結果做出abort的回滾策略,此時向各個參與者節點發起abort的回滾操做,即:

這個時候參與者節點接收到事務回滾操做,將原先保存的undo數據進行恢復,而後將回滾的操做結果響應給協調者,協調者接收到全部參與者節點回滾的響應結果,向客戶端發起事務操做失敗的響應結果.

2PC產生阻塞
  • 協調者發起請求的時候會等待參與者的響應結果
  • 參與者接收到協調者發起的請求並給予響應此時也處於等待狀態,等待提交redo或者回滾undo
  • 此時參與者接收到應答指令執行相應的操做以後,協調者會繼續處於等待參與者處理的結果響應
  • 同時,既然是分佈式系統,必然離不開網絡服務之間的通信以及機器節點的故障問題,於是若是協調者產生不可用,此時全部的參與者將會一直處於阻塞狀態
2PC產生數據不一致
  • 當協調者向參與者發起提交或者是回滾操做的時候,其中有一個參與者服務節點產生不可用的狀況,這個時候參與者節點將沒法接收到提交或者回滾信息,那麼這個時候就會產生數據不一致.
2PC的總體流程總結

3PC事務協議

在實際應用場景中,3PC的使用場景並很少,大部分是基於2pc的實現來完成分佈式事務,甚至是爲了保證數據的強一致性會採起TCC的事務協議來完成,對於3PC現簡單闡述以下:

3PC提交過程說明
  • 協調者服務節點發起事務請求給到參與者節點詢問是否容許事務請求提交
  • 參與者節點接收到事務請求提交以後將當前數據記錄到undo日誌中,以便於後續請求的超時或者是無響應進行事務的回滾,這個時候記錄undo日誌以後返回給協調者告知請求提交的結果
  • 協調者此時若是沒有接收到參與者的請求提交響應回覆抑或是拒絕請求提交將終止當前操做再也不繼續下一步;若是收到容許請求提交操做,則會向參與者節點發起預提交請求到參與者節點中
  • 參與者節點若是沒有接收到預提交的請求抑或是網絡延遲中斷,那麼就會將上次的undo日誌進行數據回覆並丟棄當前的事務操做;若是能正確接收到預提交的請求操做,那麼這個時候會將更新的數據記錄到redo日誌中,以便於後續進行持久化.
  • 對於協調者而言,若是正確接收到預提交請求的ACK響應,那麼這個時候將會執行請求提交到參與者節點;若是沒有接收到ACK的響應抑或是網絡超時問題,將會直接丟棄當前的事務操做.
  • 而對於第三階段的確認提交,參與者節點不管是網絡中斷仍是超時抑或是正常接收到doCommit的提交請求操做,那麼這個時候都會執行redo日誌進行持久化操做並響應給協調者節點告知當前事務操做完成而且已經提交.
3PC存在的數據不一致問題
經過上述的流程分析,咱們很容易得出,3PC的事務協議提交階段存在的數據不一致主要體如今:
在協調者進行預提交階段,協調者服務節點向參與者節點發起預提交請求,其中向參與者集羣服務節點已成功發起預提交請求,可是這個時候協調者服務節點發生故障致使不可用,那麼就會致使參與者節點服務部分沒有收到預提交的請求,這個時候這部分參與者節點因爲沒有收到preCommit請求而進行undo日誌的回滾.
TCC事務協議
TCC定義
TCC,即Try(預留資源)-Confirm(確認操做)-Cancel(撤銷操做),其核心流程以下:

TCC原理分析
  • 在主服務節點註冊一個確認以及撤銷的操做,而後在主服務節點開啓事務執行資源的鎖定並預留可用的資源,而後提交消息分發到各個子服務節點中
  • 子服務節點接收到主服務節點的事務操做消息,這個時候子服務也將本身對應的資源進行鎖定,同時也將可用的資源預留出來以便於提高併發操做的性能,而後向主服務節點推送操做結果的消息爲Success或者是Fail
  • 主服務節點根據各個子服務節點操做結果的反饋,若是存在一個子服務節點的Fail反饋,那麼就執行撤銷回滾操做並將鎖定的資源回收到資源池中來保證整個分佈式事務的ACID,若是返回都是Success,那麼就執行確認操做釋放鎖定資源.最後將操做結果以消息的形式分發到各個子服務節點上
  • 子服務節點接收到主服務節點的事務確認或者回滾消息,也將執行相應的確認或者是回滾操做,若是是回滾操做,那麼一樣也將鎖定的資源回收到資源池中,若是是執行確認操做,那麼就釋放資源.
能夠看到TCC是創建在業務基礎上來保證分散的服務節點的事務一致性,實現相對比2PC更爲複雜些.
TCC各個服務節點運做
以一個送禮下單爲例展開,現有一個訂單服務,禮物服務以及用戶積分服務.以下圖所示:

訂單服務能夠認爲是一個主服務,主要負責訂單狀態的更新,而禮物服務以及積分服務做爲一個子服務,負責更新禮物庫存以及積分信息.因而對於一個TCC的操做流程能夠分解爲以下幾個步驟:

  • 訂單服務接收到送禮下單的請求,那麼這個時候訂單服務將會建立一個訂單並設置當前的訂單狀態爲PENDING以便於提高併發性能查詢而並不是處於建立訂單的阻塞等待狀態,同時分發消息到禮物服務以及積分服務.

  • 禮物服務以及積分服務分別收到訂單服務發出的事務操做請求命令,這個時候禮物服務以及積分服務分別記錄redo以及undo日誌,redo能夠理解爲可用資源提供外界查詢以實現併發訪問的性能,undo鎖定使用的資源以便於回滾,這裏的redo能夠是對應的數據庫已發生變動數據的記錄,undo日誌記錄變動前的數據並設置爲鎖定狀態.而後將操做結果返回給訂單服務節點.

  • 訂單服務節點更新返回的子服務消息結果,若是都是操做成功,那麼這個時候就執行確認操做,訂單服務將訂單狀態更新爲FINISHED,並將消息分發到各個服務節點,若是存在一個節點操做失敗,則執行更新狀態爲REJECTED,並下發回滾操做的消息.

基於上述的認知以後,咱們要實現一個基於TCC的分佈式事務,若是在沒有使用開源產品的場景下,最簡單的方式是能夠基於MQ的方式來實現可靠消息的生產與消費從而實現咱們的分佈式事務協議TCC.




BASE理論

BASE理論定義

BASE是Basically Available(基本可用),Soft Sate(軟狀態)以及Eventual Consistency(最終一致性)三個短語的縮寫.

  • 基本可用:多是部分功能不可用或者是因網絡緣由響應時間延遲致使延遲的時間段內不可用

  • 軟狀態:集羣服務節點在進行數據同步期間數據的過渡狀態.好比一個事務操做前爲v1,進行事務操做後爲v2,節點服務之間數據由v1轉變爲v2的狀態爲過渡狀態.

  • 最終一致性:通過系統內部服務之間的運行協做,最終服務節點表如今業務上抑或是集羣leader選舉或者是數據上等最終保持一致性

數據一致性模型
  • 線性一致性(強一致性): 不管是在集羣服務哪一個節點,看到的數據最終都是一致性.

  • 順序一致性(弱一致性): 集羣服務節點的數據變更以及操做順序保持一致.

  • 最終一致性(弱一致性): 集羣的全部服務節點最終都會呈現數據的一致性

基本可用策略
  • 流量削峯:應對高併發量衝擊,能夠從如下幾個方面來考慮問題,一個是錯開時間段;一個是限流+錯開時間段,好比預定搶購;一個是在邊緣節點抑或是負責均衡器作流控;一個是在應用程序中基於MQ消息隊列來作緩衝;一個是在底層數據庫表採起分區表,不夠再進行分庫分表設計.

  • 延遲響應: 好比在進行購票的時候,咱們會提交購票請求而後須要進入系統的排隊等候,等待請求被處理.

  • 降級: 一個是當被調用的服務依賴不可用時,爲了服務調用者節點時可用的,須要加入異常處理的降級操做;又或者是在負載均衡器中發現後端服務不可用的時候能夠採起降級返回錯誤提示等

  • 過載保護: 在搶購或者是秒殺系統中,能夠考慮在nginx中進行限流而後將超出的流量直接放回搶購失敗;抑或是在應用服務中的線程池中將任務添加到阻塞隊列中,若是隊列滿了能夠考慮直接丟棄任務策略.

參考文檔
## 有狀態與無狀態服務
https://nordicapis.com/defining-stateful-vs-stateless-web-services/

## CAP定理
https://dzone.com/articles/understanding-the-cap-theorem
https://dzone.com/articles/quick-notes-what-cap-theorem

關於一致性的詳細分析留到下一篇文章中.



最後感謝花時間閱讀,若是有收穫歡迎動一動小手指轉發或者好看,謝謝!




你好,我是疾風先生,前後從事外企和互聯網大廠的java和python工做, 記錄並分享我的技術棧,歡迎關注個人公衆號,致力於作一個有深度,有廣度,有故事的工程師,歡迎成長的路上有你陪伴,關注後回覆greek可添加私人微信,歡迎技術互動和交流,謝謝!

老鐵們關注走一走,不迷路



      有用就點個好看吧   

本文分享自微信公衆號 - 疾風先生(Gale2Writing)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索