在單機場景下,可使用語言的內置鎖來實現進程同步。可是在分佈式場景下,須要同步的進程可能位於不一樣的節點上,那麼就須要使用分佈式鎖。node
阻塞鎖一般使用互斥量來實現:算法
1 和 0 能夠用一個整型值表示,也能夠用某個數據是否存在表示。數據庫
得到鎖時向表中插入一條記錄,釋放鎖時刪除這條記錄。惟一索引能夠保證該記錄只被插入一次,那麼就能夠用這個記錄是否存在來判斷是否存於鎖定狀態。網絡
存在如下幾個問題:app
使用 SETNX(set if not exist)指令插入一個鍵值對,若是 Key 已經存在,那麼會返回 False,不然插入成功並返回 True。分佈式
SETNX 指令和數據庫的惟一索引相似,保證了只存在一個 Key 的鍵值對,那麼能夠用一個 Key 的鍵值對是否存在來判斷是否存於鎖定狀態。spa
EXPIRE 指令能夠爲一個鍵值對設置一個過時時間,從而避免了數據庫惟一索引實現方式中釋放鎖失敗的問題。3d
使用了多個 Redis 實例來實現分佈式鎖,這是爲了保證在發生單點故障時仍然可用。日誌
Zookeeper 提供了一種樹形結構的命名空間,/app1/p_1 節點的父節點爲 /app1。blog
爲一個節點註冊監聽器,在節點狀態發生改變時,會給客戶端發送消息。
若是一個已經得到鎖的會話超時了,由於建立的是臨時節點,因此該會話對應的臨時節點會被刪除,其它會話就能夠得到鎖了。能夠看到,Zookeeper 分佈式鎖不會出現數據庫的惟一索引實現的分佈式鎖釋放鎖失敗問題。
一個節點未得到鎖,只須要監聽本身的前一個子節點,這是由於若是監聽全部的子節點,那麼任意一個子節點狀態改變,其它全部子節點都會收到通知(羊羣效應),而咱們只但願它的後一個子節點收到通知。
指事務的操做位於不一樣的節點上,須要保證事務的 ACID 特性。
例如在下單場景下,庫存和訂單若是不在同一個節點上,就涉及分佈式事務。
兩階段提交(Two-phase Commit,2PC),經過引入協調者(Coordinator)來協調參與者的行爲,並最終決定這些參與者是否要真正執行事務。
協調者詢問參與者事務是否執行成功,參與者發回事務執行結果。
若是事務在每一個參與者上都執行成功,事務協調者發送通知讓參與者提交事務;不然,協調者發送通知讓參與者回滾事務。
須要注意的是,在準備階段,參與者執行了事務,可是還未提交。只有在提交階段接收到協調者發來的通知後,才進行提交或者回滾。
全部事務參與者在等待其它參與者響應的時候都處於同步阻塞狀態,沒法進行其它操做。
協調者在 2PC 中起到很是大的做用,發生故障將會形成很大影響。特別是在階段二發生故障,全部參與者會一直等待,沒法完成其它操做。
在階段二,若是協調者只發送了部分 Commit 消息,此時網絡發生異常,那麼只有部分參與者接收到 Commit 消息,也就是說只有部分參與者提交了事務,使得系統數據不一致。
任意一個節點失敗就會致使整個事務失敗,沒有完善的容錯機制。
本地消息表與業務數據表處於同一個數據庫中,這樣就能利用本地事務來保證在對這兩個表的操做知足事務特性,而且使用了消息隊列來保證最終一致性。
分佈式系統不可能同時知足一致性(C:Consistency)、可用性(A:Availability)和分區容忍性(P:Partition Tolerance),最多隻能同時知足其中兩項。
一致性指的是多個數據副本是否能保持一致的特性,在一致性的條件下,系統在執行數據更新操做以後可以從一致性狀態轉移到另外一個一致性狀態。
對系統的一個數據更新成功以後,若是全部用戶都可以讀取到最新的值,該系統就被認爲具備強一致性。
可用性指分佈式系統在面對各類異常時能夠提供正常服務的能力,能夠用系統可用時間佔總時間的比值來衡量,4 個 9 的可用性表示系統 99.99% 的時間是可用的。
在可用性條件下,要求系統提供的服務一直處於可用的狀態,對於用戶的每個操做請求老是可以在有限的時間內返回結果。
網絡分區指分佈式系統中的節點被劃分爲多個區域,每一個區域內部能夠通訊,可是區域之間沒法通訊。
在分區容忍性條件下,分佈式系統在遇到任何網絡分區故障的時候,仍然須要能對外提供一致性和可用性的服務,除非是整個網絡環境都發生了故障。
在分佈式系統中,分區容忍性必不可少,由於須要老是假設網絡是不可靠的。所以,CAP 理論其實是要在可用性和一致性之間作權衡。
可用性和一致性每每是衝突的,很難使它們同時知足。在多個節點之間進行數據同步時,
BASE 是基本可用(Basically Available)、軟狀態(Soft State)和最終一致性(Eventually Consistent)三個短語的縮寫。
BASE 理論是對 CAP 中一致性和可用性權衡的結果,它的核心思想是:即便沒法作到強一致性,但每一個應用均可以根據自身業務特色,採用適當的方式來使系統達到最終一致性。
指分佈式系統在出現故障的時候,保證核心可用,容許損失部分可用性。
例如,電商在作促銷時,爲了保證購物系統的穩定性,部分消費者可能會被引導到一個降級的頁面。
指容許系統中的數據存在中間狀態,並認爲該中間狀態不會影響系統總體可用性,即容許系統不一樣節點的數據副本之間進行同步的過程存在時延。
最終一致性強調的是系統中全部的數據副本,在通過一段時間的同步後,最終能達到一致的狀態。
ACID 要求強一致性,一般運用在傳統的數據庫系統上。而 BASE 要求最終一致性,經過犧牲強一致性來達到可用性,一般運用在大型分佈式系統中。
在實際的分佈式場景中,不一樣業務單元和組件對一致性的要求是不一樣的,所以 ACID 和 BASE 每每會結合在一塊兒使用。
用於達成共識性問題,即對多個節點產生的值,該算法能保證只選出惟一一個值。
主要有三類節點:
規定一個提議包含兩個字段:[n, v],其中 n 爲序號(具備惟一性),v 爲提議值。
下圖演示了兩個 Proposer 和三個 Acceptor 的系統中運行該算法的初始過程,每一個 Proposer 都會向全部 Acceptor 發送 Prepare 請求。
當 Acceptor 接收到一個 Prepare 請求,包含的提議爲 [n1, v1],而且以前還未接收過 Prepare 請求,那麼發送一個 Prepare 響應,設置當前接收到的提議爲 [n1, v1],而且保證之後不會再接受序號小於 n1 的提議。
以下圖,Acceptor X 在收到 [n=2, v=8] 的 Prepare 請求時,因爲以前沒有接收過提議,所以就發送一個 [no previous] 的 Prepare 響應,設置當前接收到的提議爲 [n=2, v=8],而且保證之後不會再接受序號小於 2 的提議。其它的 Acceptor 相似。
若是 Acceptor 接收到一個 Prepare 請求,包含的提議爲 [n2, v2],而且以前已經接收過提議 [n1, v1]。若是 n1 > n2,那麼就丟棄該提議請求;不然,發送 Prepare 響應,該 Prepare 響應包含以前已經接收過的提議 [n1, v1],設置當前接收到的提議爲 [n2, v2],而且保證之後不會再接受序號小於 n2 的提議。
以下圖,Acceptor Z 收到 Proposer A 發來的 [n=2, v=8] 的 Prepare 請求,因爲以前已經接收過 [n=4, v=5] 的提議,而且 n > 2,所以就拋棄該提議請求;Acceptor X 收到 Proposer B 發來的 [n=4, v=5] 的 Prepare 請求,由於以前接收到的提議爲 [n=2, v=8],而且 2 <= 4,所以就發送 [n=2, v=8] 的 Prepare 響應,設置當前接收到的提議爲 [n=4, v=5],而且保證之後不會再接受序號小於 4 的提議。Acceptor Y 相似。
當一個 Proposer 接收到超過一半 Acceptor 的 Prepare 響應時,就能夠發送 Accept 請求。
Proposer A 接收到兩個 Prepare 響應以後,就發送 [n=2, v=8] Accept 請求。該 Accept 請求會被全部 Acceptor 丟棄,由於此時全部 Acceptor 都保證不接受序號小於 4 的提議。
Proposer B 事後也收到了兩個 Prepare 響應,所以也開始發送 Accept 請求。須要注意的是,Accept 請求的 v 須要取它收到的最大提議編號對應的 v 值,也就是 8。所以它發送 [n=4, v=8] 的 Accept 請求。
Acceptor 接收到 Accept 請求時,若是序號大於等於該 Acceptor 承諾的最小序號,那麼就發送 Learn 提議給全部的 Learner。當 Learner 發現有大多數的 Acceptor 接收了某個提議,那麼該提議的提議值就被 Paxos 選擇出來。
指只有一個提議值會生效。
由於 Paxos 協議要求每一個生效的提議被多數 Acceptor 接收,而且 Acceptor 不會接受兩個不一樣的提議,所以能夠保證正確性。
指最後總會有一個提議生效。
Paxos 協議可以讓 Proposer 發送的提議朝着能被大多數 Acceptor 接受的那個提議靠攏,所以可以保證可終止性。
Raft 也是分佈式一致性協議,主要是用來競選主節點。
有三種節點:Follower、Candidate 和 Leader。Leader 會週期性的發送心跳包給 Follower。每一個 Follower 都設置了一個隨機的競選超時時間,通常爲 150ms~300ms,若是在這個時間內沒有收到 Leader 的心跳包,就會變成 Candidate,進入競選階段。