(轉)分佈式原理

ACID vs BASE vs CAP

CAP:首先Eric Brewer, a professor at the University of California, Berkeley, and cofounder and chief scientist at Inktomi提出了CAP理論:CAP: Consistency, Availability and Tolerance of network     Partition。並證實了CAP最多隻能同時知足兩個。He presented the CAP theorem, which states that of three properties of shared-data systems—data consistency, system availability, and tolerance to network partition—only two can be achieved at any given time. A more formal confirmation can be found in a 2002 paper by Seth Gilbert and Nancy Lynch.那麼若是要知足all-or-nothing的原子性和強一致性,這也是ACID事務所要知足的需求,就不得不犧牲可用性。若是想要得到可用性和P(tolerance of network partition).那就不得不犧牲一致性,也就不存在原子性,這也就是BASE所能知足的需求。 

ACID: Atomicity, Consistency, Isolation, Durability. 

BASE: Basic Available, Soft-state, Eventual Consistency. 

Eric Brewer這裏的C值得不是ACID中的一致性,而是原子性。 
CAP 
證實爲何CAP不能三個同時知足 
The Proof in Pictures 


在Network N1和N2中分別有兩個node A和B,這兩個節點上面都包含數據V0(天龍八部在貨倉中的數目)。 

在某一個星期日,A將本身的數量從V0更新到V1,並通知B,更新到V1。這樣任何從B讀出的書的數目也是V1。 

若是網絡出現分區則A更新到V1以後B仍然是V0。 
開始討論了:1)若是不考慮分區耐受性,那麼很簡單N1只須要將本身更新而不須要考慮N2,當有消息的時候只須要讀取A。若是A失敗了那麼網絡也就失敗了。這至關於一個單機系統那麼是能夠保證Consistency&Availability的。2)若是要保證分區耐受性,也就是也可以從B讀取數據。若是犧牲Availability,那麼更新數據的時候A使用兩階段提交協議將B鎖住就能夠保證A和B的數據是一致的。或者說存在另外的一個Coordinator用兩階段提交協議更新數據,將A和B都鎖住。若是犧牲一致性,那麼就能夠直接更新A和B而不須要考慮是否知足consistency。 

假設有這樣的一個transaction,a1階段write,a2階段read。若是實在一個單機系統上,經過簡單的寫鎖是能夠控制系統的一致性和可用性的,只是須要儘可能縮短synch的時間。可是在分佈式系統裏面,因爲各類緣由很難控制synch的時間。咱們只能控制何時a2開始,可是咱們不能保證在a2開始的時候必定能讀到a1寫的數據。 

ACID 
    知足ACID屬性又被稱爲是事務,被普遍應用在以數據庫爲表明的對可靠性和安全性有極高需求的應用場景。單對於Atomicity(原子性)數據庫領域和操做系統領域的理解是有相應差別的。在數據庫領域原子性指的是all-or-nothing的原子性,而操做系統是指一個操做在沒有完成以前是不能被其餘操做干預的,其實是isolation的原子性。原子性和隔離性又是實現一致性的基礎。 
    持久性知足當對數據提出需求時,數據扔然可以被正常讀取。根據不一樣的場景,對持久性提出了不一樣程度的要求。計算機的一條指令只須要寄存器級別的持久性,運行程度的中間變量須要的是內存級別的持久性,而文件系統須要硬盤級別的持久性,爲了得到更高級別的持久性,並防止由於硬盤故障或者是網絡故障致使的沒法正常讀取數據的問題,產生了將數據分片存儲的需求(如RAID)。或者將數據備份如(Master-Slave架構)。 
    對於採用分片或者M-S結構的持久性實現方式,對於一致性提出了新的挑戰。在某種程度上能夠認爲,分佈式系統的一致性問題的根源來源於爲了保證系統的持久性也就是可靠性。 

BASE 
    研究BASE就須要和REST作對比,由於這是衡量一個互聯網應用的準則。不一樣於ACID面相的商業應用,互聯網應用對可用性的要求更高,而對可靠性的要求在某種意義上要比商業應用低。 

BASE的應用場景 
你是怎樣爲像「出價競拍」這樣的操做實現原子性的? 
                出價競拍自己就是一個頗有意思的問題,原子性並非重點,更多的是關係到在拍賣關鍵的最後幾秒鐘裏不要阻塞任何出價人。若是改爲在顯示時刻而不是在出價時刻計算最高出價人和最高出價,就會變得很是簡單。全部出價都被插入到一個單獨的子表,插入操做不太會引發資源爭用的狀況。每次顯示產品的時候,再從新取回全部的出價,而且在這個時候應用業務邏輯來決定最高的出價人。 
                你的問題背後隱藏的真正問題是咱們如何實現一致性?要在大型系統中實現一致性,你必須放棄ACID,轉而使用BASE: 
                基本可用(Basically Available) 
                軟狀態(Soft state) 
                最終一致(Eventually consistent) 
                若是你可以在每一個客戶端請求快結束的時候放鬆對數據一致的要求,就有可能消除分佈式事務,並使用其它機制來達成一致的狀態。舉例來講,在上面的出價案例中,咱們也更新視圖數據表,視圖數據表是按照出價人來組織數據的,目的是加速「個人eBay」頁面的顯示。這裏用兩個異步事件來完成。一個是依靠內存中的隊列,由於咱們但願儘可能縮短從出價到在顯示在「個人eBay」頁面上之間的響應時間。可是,內存中的隊列不可靠,因此在發生出價操做的時候,咱們同時用一個服務器端事務來捕獲出價事件。即便內存中隊列的操做失敗了,這個出價事件也能根據還原機制被處理。出價人視圖數據表所以而解耦,但不老是與出價表的狀態保持一致。不過這是咱們能夠接受的讓步,它讓出價表和出價視圖表之間沒必要服從ACID要求。node

一致性&持久性

1.      什麼是一致性、持久性以及事務 

當一個原子操做具備了一致性,隔離性和持久性以後,這個原子操做就能夠被稱爲事務。 
Consistency is an application-defined requirement that every update to a collection of data must preserve some specified invariant. Different applications can have quite different consistency invariants. 
咱們一直討論一致性,並將一致性理解爲咱們所看到的數據和一系列操做所更新的數據是一致的。可是實際上這並非一致性的最本質的含義。本質的含義是,根據應用的需求,咱們對一系列數據集的操做要維持一個不變量。例如,表的行號應和行數是對應的。cache應和後臺數據是對應的。 

書中花費了很大段討論Atomicity。原子性分爲all-of-nothing atomicity和isolation atomicity. 

強一致性:就是將不一致隱藏在系統邊緣內部。從外部看任什麼時候候系統都是一致的。 
最終一致性:主要表如今更新數據時,有一段時間從系統邊緣外看,是不一致的,可是在某個時間段後,一致性會獲得保證。 

有時最終一致性反卻是一個優勢。好比Download一個網頁時,先出現文字,後出現圖片。在download過程當中,頁面與後臺數據是不一致的,可是這反而改善了用戶體驗。 

2.      Cache coherence 

Cache的一致性要求在於Cache中存儲的數據應當和二級存儲中的數據應當的相等的。可是因爲從Cache到二級存儲的延遲,存在某個時間段,Cache和二級存貯中的數據是不一樣的。 

Cache應當知足讀寫一致性:The result of a read of a named object is always the value of the 
most recent write to that object. 
請求對一個Object讀,讀到的應該是最近一次寫的結果。 
Cache分紅: 
1.         Write through cache(直寫式緩存)每次寫操做不光寫cache還寫到二級存儲,這樣就容易形成性能的瓶頸。 
2.         Write back cache(回寫式緩存)先是將寫操做寫到cache中,這時應用就能夠認爲寫操做已經完成了。而將cache中的數據更新到二級存儲是由cache manager來完成。 
若是隻有一個cache那麼回寫式緩存也可以提供強一致性,可是若是thread可以直接從二級緩存讀數據或者有多個cache,可能其中某個cache並非最新數據那麼一致性就受到了破壞。 

如何在分佈式緩存中仍然可以得到一致性? 
1.         若是shared和writable的數據不多,那麼能夠將這些數據標示成「不可緩存」。 
a)         World Wide Web採用了這種方式。在HTTP頭有一個字段,能夠設置「不可緩存」這樣Web Page就不會被緩存。 
b)        Java內存模型中一種思想相似的方法是將一個變量聲明爲volatile。 
2.         另一種思想是將那些與權威副本不一致的緩存標示爲無效。 
a)         一個設計思想,若是在多個處理器共享的二級存儲上共享cache,則能夠避免不一致性。可是共享cache會致使處理器對cache的競爭和互斥。這樣會下降系統性能。所以對於每一個處理器提供一個單獨的私有的cache。這樣就產生了不一致性。即便是使用直寫式緩存,處理器A對數據Data的更新卻沒法寫處處理器B的私有緩存上,這樣就致使了不一致性。這就須要有一種機制去告訴那些使用了數據Data的處理器,數據Data已經失效。 
                         i.              當有一個處理器寫的時候,告訴其餘全部處理器他們的私有緩存所有都失效了。 
另一種方法是使用更多的wire,去告訴其餘私有緩存內存中的那個地址的數據失效了。一種方法就是私有緩存都偵聽memory bus。當memory bus上有寫操做的時候。A slightly more clever 
design will also grab the data value from the bus as it goes by and update, rather than invalidate, its copy of that data. These are two variations on what is called the snoopy cache*—each cache is snooping on bus activity. 
                       ii.              即便使用了Snoopy Cache仍然會遇到問題。cache的問題解決了,可是register卻會帶來新的同步問題。 
3.         只要是容許副本被多個請求併發的訪問,如何維護隔離性和一致性就是一個複雜的問題。採用鎖的方式避免併發訪問是一種解法,可是又會影響到性能。一種可行的方法是使用機率。 
3.      持久性,以及有多個副本帶來的一致性問題 

持久性就會帶來多個副本之間的一致性問題:下面都是處理多個副本之間的不一致性。 
The durability mantra 
Multiple copies, widely separated and independently administered… 
Multiple copies, widely separated and independently administered… 

1.         Replicated state machine 
If the data is written exactly once and never again changed, the management plan can be fairly straightforward。這個是Hadoop和Cassandra可以保證多個副本一致的前提。 
2.        Master and Slave結構 
M/S結構的一個很大的弱點就是M更新的時候,讀S讀到的都是舊的數據。設計一個MS的結構會面對一系列的問題:好比M和S瞬時的不一致。還有就是M的數據decay了,S若是尚未同步,則同步的數據也是錯誤的。 
3.        保證分佈式數據的完整性? 
a)        能夠在副本之間作校驗,可是一旦這些數據之間的傳輸開銷很大的話,聚會形成很大的時間成本。 
b)        並非直接對比而是傳輸MD5checksum 
總結: 
1)簡單副本(RAID)2)爲了不地震等故障,更加分佈的副本GFS3)按照某種邏輯寫數據,也就是你們寫數據的時候都遵循必定的規則,從而避免不一致的狀況4)運用機率提高性能5)Replicated state machines6)Master/Slave結構->爲了不M和S的不一致性,能夠將M的表劃分細小,而後每一個細小的表有一個Master->爲了不M和S的不一導致用兩階段提交協議->當M失效以後使用選舉算法選出新的Master->If the application is one in which the data is insensitive to the order of updates, implement a replicated state machine without a consensus algorithm.->增量更新->傳遞的不是增量而是操做的log7)quorum算法 
4.      協調(Reconciliation)算法 

什麼是協調?當系統update到一半,或者M-S結構裏面M宕機了,或者數據副本出現不一致狀態了。那麼從這種不「和諧」的狀態從新歸於「和諧」就是reconciliation。 
1.          Occasionally connected operation 
這個場景就例如iphone和iMac之間的數據同步。更好的比喻是SVN,client和SVN上面文件的同步。 
如何發現文件之間的不一樣: 
a)       checksum 
b)       維護一個統一的文件id,一旦產生變化就將id加1。 
c)       經過時間戳。文件更改了則時間戳就會更新。 
5.      Atomicity across layers and multiple sites 

   兩階段提交協議的兩個階段:(注意區分兩階段提交協議2PC和兩階段鎖協議2PL) 
達成協議階段: 
在這個階段協調者向全部要執行commit操做的節點發出「嘗試commit」的請求。節點接受到請求後「嘗試commit」,例如包括更新log——在undo log中增長新的信息,在redo log中增長新信息。當發現能夠正常的commit,則返回一個Yes的消息,不然返回一個No的消息表示abort。 
若是coordinator收到了所有的Yes消息,則發出一個commit消息,則全部的節點都commit,並釋放佔有的資源鎖。 
若是coordinator收到的消息中有No消息,表示某個節點不可以commit,則coordinator羣發一個rollback的消息。這時每一個節點根據undo log中的日誌回滾,而後釋放佔用的資源鎖。這裏正是memento模式的用武之地! 
缺點: 
這是一個異步協議,對系統的可用性影響極大;若是coordinator失效了,可能會致使一些node的鎖永遠不會被釋放,被永遠綁定。若是node向coordinator發送了agreement消息,並等待commit或者rollback的反饋。若是這個時候coordinator掛了,這個就會被永遠鎖住,除非從其餘的coordinator那裏能獲得相應的反饋。 
當coordinator發送一個「Query-to-commit」消息的時候,在收到全體相應以前coordinator也是被阻塞的。可是若是一個node沒有響應,coordinator不會被永久阻塞。由於coordinator能夠引入一個timeout機制避免被永久阻塞。 
由於上面提到的time out機制,這個協議的另一大弱點是:偏向於abort一個case,而不是complete一個case。 
Implementing the two-phase commit protocol 

    6.    一致性判別 

    數據一致性一般指關聯數據之間的邏輯關係是否正確和完整。而數據存儲的一致性模型則能夠認爲是存儲系統和數據使用者之間的一種約定。若是使用者遵 循這種約定,則能夠獲得系統所承諾的訪問結果。 
經常使用的一致性模型有: 
嚴格一致性(linearizability, strict/atomic Consistency):讀出的數據始終爲最近寫入的數據。這種一致性只有全局時鐘存在時纔有可能,在分佈式網絡環境不可能實現。 
弱一致性(weak consistency):只要求對共享數據結構的訪問保證順序一致性。對於同步變量的操做具備順序一致性,是全局可見的,且只有當沒有寫操做等待處理時 纔可進行,以保證對於臨界區域的訪問順序進行。在同步時點,全部使用者能夠看到相同的數據。 
最終一致性(eventual consistency):當沒有新更新的狀況下,更新最終會經過網絡傳播到全部副本點,全部副本點最終會一致,也就是說使用者在最終某個時間點前的中間 過程當中沒法保證看到的是新寫入的數據。能夠採用最終一致性模型有一個關鍵要求:讀出陳舊數據是能夠接受的。   
順序一致性(sequential consistency):全部使用者以一樣的順序看到對同一數據的操做,可是該順序不必定是實時的。 
因果一致性(causal consistency):只有存在因果關係的寫操做纔要求全部使用者以相同的次序看到,對於無因果關係的寫入則並行進行,無次序保證。因果一致性能夠看 作對順序一致性性能的一種優化,但在實現時必須創建與維護因果依賴圖,是至關困難的。 
管道一致性(PRAM/FIFO consistency):在因果一致性模型上的進一步弱化,要求由某一個使用者完成的寫操做能夠被其餘全部的使用者按照順序的感知到,而從不一樣使用者中 來的寫操做則無需保證順序,就像一個一個的管道同樣。 相對來講比較容易實現。 
釋放一致性(release consistency):弱一致性沒法區分使用者是要進入臨界區仍是要出臨界區, 釋放一致性使用兩個不一樣的操做語句進行了區分。須要寫入時使用者acquire該對象,寫完後release,acquire-release之間造成了 一個臨界區,提供 釋放一致性也就意味着當release操做發生後,全部使用者應該能夠看到該操做。 
delta consistency:系統會在delta時間內達到一致。這段時間內會存在一個不一致的窗口,該窗口多是由於log shipping的過程致使。 

最終一致性的幾種具體實現: 
一、讀不舊於寫一致性(Read-your-writes consistency):使用者讀到的數據,老是不舊於自身上一個寫入的數據。 
二、會話一致性(Session consistency):比讀不舊於寫一致性更弱化。使用者在一個會話中才保證讀寫一致性,啓動新會話後則無需保證。 
三、單讀一致性(Monotonic read consistency):讀到的數據老是不舊於上一次讀到的數據。 
四、單寫一致性(Monotonic write consistency):寫入的數據完成後才能開始下一次的寫入。 
五、寫不舊於讀一致性(Writes-follow-reads consistency):寫入的副本不舊於上一次讀到的數據,即不會寫入更舊的數據. 
六、選舉一致性: 
Werner Vogels認爲:在不少互聯網應用中,單讀一致性+讀不舊於寫一致性能夠提供足夠的一致性了。 es6

相關文章
相關標籤/搜索