任老師第一節主要講了分布式系統實現時候面臨的八個問題,布置的作業就是這個,查詢CAP理論。
筆者初次接觸分布式,所以本文主要是一個匯總。
一.CAP起源
CAP原本是一個猜想,2000年PODC大會的時候大牛Brewer提出的,他認為在設計一個大規模可擴放的網絡服務時候會遇到三個特性:一致性(consistency)、可用性(Availability)、分區容錯(partition-tolerance)都需要的情景,然而這是不可能都實現的。之后在2003年的時候,Mit的Gilbert和Lynch就正式的證明了這三個特征確實是不可以兼得的。該理論是NoSQL數據庫管理系統構建的基礎。。
Consistency、Availability、Partition-tolerance的提法是由Brewer提出的,而Gilbert和Lynch在證明的過程中改變了Consistency的概念,將其轉化為Atomic。Gilbert認為這里所說的Consistency其實就是數據庫系統中提到的ACID的另一種表述:
一個用戶請求要么成功、要么失敗,不能處於中間狀態(Atomic);
一旦一個事務完成,將來的所有事務都必須基於這個完成后的狀態(Consistent);
未完成的事務不會互相影響(Isolated);
一旦一個事務完成,就是持久的(Durable)。
對於Availability,其概念沒有變化,指的是對於一個系統而言,所有的請求都應該‘成功’並且收到‘返回’。
對於Partition-tolerance,所指就是分布式系統的容錯性。節點crash或者網絡分片都不應該導致一個分布式系統停止服務。
二.CAP簡介
CAP定律說的是在一個分布式計算機系統中,一致性,可用性和分區容錯性這三種保證無法同時得到滿足,最多滿足兩個。
2.1 強一致性
強一致性:系統在執行過某項操作后仍然處於一致的狀態。在分布式系統中,更新操作執行成功后所有的用戶都應該讀到最新的值,這樣的系統被認為是具有強一致性的。 等同於所有節點訪問同一份最新的數據副本;
All clients always have the same view of the data。
2.2 可用性
可用性:每一個操作總是能夠在一定的時間內返回結果,這里需要注意的是"一定時間內"和"返回結果"。一定時間指的是,在可以容忍的范圍內返回結果,結果可以是成功或者失敗。 對數據更新具備高可用性(A);
Each client can alwa read and write。
2.3 分區容錯性
分區容錯性:理解為在存在網絡分區的情況下,仍然可以接受請求(滿足一致性和可用性)。這里的網絡分區是指由於某種原因,網絡被分成若干個孤立的區域,而區域之間互不相通。還有一些人將分區容錯性理解為系統對節點動態加入和離開的能力,因為節點的加入和離開可以認為是集群內部的網絡分區。
Partition Tolerance的意思是,在網絡中斷,消息丟失的情況下,系統照樣能夠工作。 以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味着發生了分區的情況,必須就當前操作在C和A之間做出選擇
2.4 放棄C.A.P
放棄P:如果想避免分區容錯性問題的發生,一種做法是將所有的數據(與事務相關的)都放在一台機器上。雖然無法100%保證系統不會出錯,但不會碰到由分區帶來的負面效果。當然這個選擇會嚴重的影響系統的擴展性。
放棄A:相對於放棄“分區容錯性“來說,其反面就是放棄可用性。一旦遇到分區容錯故障,那么受到影響的服務需要等待一定的時間,因此在等待期間系統無法對外提供服務。
放棄C:這里所說的放棄一致性,並不是完全放棄數據一致性,而是放棄數據的強一致性,而保留數據的最終一致性。以網絡購物為例,對只剩下一件庫存的商品,如果同時接受到了兩份訂單,那么較晚的訂單將被告知商品告罄。
一致性與可用性的決擇: 而CAP理論就是說在分布式存儲系統中,最多只能實現上面的兩點。而由於當前的網絡硬件肯定 會出現延遲丟包等問題,所以分區容忍性是我們必須需要實現的。所以我們只能在一致性和可用 性之間進行權衡。
三.基本CAP的證明思路
CAP的證明基於異步網絡,異步網絡也是反映了真實網絡中情況的模型。真實的網絡系統中,節點之間不可能保持同步,即便是時鍾也不可能保持同步,所有的節點依靠獲得的消息來進行本地計算和通訊。這個概念其實是相當強的,意味着任何超時判斷也是不可能的,因為沒有共同的時間標准。之后我們會擴展CAP的證明到弱一點的異步網絡中,這個網絡中時鍾不完全一致,但是時鍾運行的步調是一致的,這種系統是允許節點做超時判斷的。
CAP的證明很簡單,假設兩個節點集{G1, G2},由於網絡分片導致G1和G2之間所有的通訊都斷開了,如果在G1中寫,在G2中讀剛寫的數據, G2中返回的值不可能G1中的寫值。由於A的要求,G2一定要返回這次讀請求,由於P的存在,導致C一定是不可滿足的。
四.CAP的理解
4.1 流行解釋
目前流行的、對CAP理論解釋的情形是從同一數據在網絡環境中存在多個副本出發為前提的。為了保證數據不會丟失,同時也是為了增加並發訪問量(讀寫分離),在企業級的數據管理方案中,一般必須考慮數據的冗余存儲問題,而這應該是通過在網絡上的其他獨立物理存儲節點上保留另一份、或多份數據副本來實現的(如附圖所示)。因為在同一個存儲節點上的數據冗余明顯不能解決單點故障問題,這與通過多節點集群來提供更好的計算可用性的道理是相同的。
如上圖的情況,數據在節點A、B、C上保留了三份,如果對節點A上的數據進行了修改,然后再讓客戶端通過網絡對該數據進行讀取。那么,客戶端的讀取操作什么時候返回呢?
一種情況是要求節點A、B、C的三份數據完全一致后返回。也就是說,這時從任何一個網絡節點讀取的數據都是一樣的,這就是所謂的強一致性讀。很明顯,這時數據讀取的Latency要高一些(因為要等數據在網絡中的復制),同時A、B、C三個節點中任何一個宕機,都會導致數據不可用。也就是說,要保證強一致性,網絡中的副本越多,數據的可用性就越差。
另一種情況是,允許讀操作立即返回,容忍B節點的讀取與A節點的讀取不一致的情況發生。這樣一來,可用性顯然得到了提高,網絡中的副本也可以多一些,唯一得不到保證的是數據一致性。當然,對寫操作同樣也有多個節點一致性的情況,在此不再贅述。
可以看出,上述對CAP理論的解釋主要是從網絡上多個節點之間的讀寫一致性出發考慮問題的。而這一點,對於關系型數據庫意味着什么呢?當然主要是指通常所說的Standby(關於分布式事務,涉及到更多考慮,隨后討論)情況。對此,在實踐中我們大多已經采取了弱一致性的異步延時同步方案,以提高可用性。這種情況並不存在關系型數據庫為保證C、A而放棄P的情況;而對海量數據管理的需求,關系型數據庫擴展過程中所遇到的性能瓶頸,似乎也並不是CAP理論中所描述的那種原因造成的。那么,上述流行的說法中所描述的關系型數據庫為保證C、A而犧牲P到底是在指什么呢? 如果只將CAP當作分布式系統中多個數據副本之間的讀寫一致性問題的通用理論對待,那么就可以得出結論:CAP既適用於NoSQL數據庫,也適用於關系型數據庫。它是NoSQL數據庫、關系型數據庫,乃至一切分布式系統在設計數據多個副本之間讀寫一致性問題時需要遵循的共同原則。
4.2 形式化描述
要真正理解 CAP 理論必須要讀懂它的形式化描述。 形式化描述中最重要的莫過於對 Consistency, Availability, Partition-tolerance 的准確定義。
Consistency (一致性) 實際上等同於系統領域的 before-or-after atomicity 這個術語,或者等同於 linearizable (可串行化) 這個術語。具體來說,系統中對一個數據的讀和寫雖然包含多個子步驟並且會持續一段時間才能執行完,但是在調用者看來,讀操作和寫操作都必須是單個的即時完成的操作,不存在重疊。對一個寫操作,如果系統返回了成功,那么之后到達的讀請求都必須讀到這個新的數據;如果系統返回失敗,那么所有的讀,無論是之后發起的,還是和寫同時發起的,都不能讀到這個數據。
要說清楚 Availability 和 Partition-tolerance 必須要定義好系統的故障模型。在形式化證明中,系統包含多個節點,每個節點可以接收讀和寫的請求,返回成功或失敗,對讀還要返回一個數據。和調用者之間的連接是不會中斷的,系統的節點也不會失效,唯一的故障就是報文的丟失。 Partition-tolerance 指系統中會任意的丟失報文(這和“最終會有一個報文會到達”是相對的)。 Availability 是指所有的讀和寫都必須要能終止。
注: “Availability 是指所有的讀和寫都必須要能終止” 這句話聽上去很奇怪,為什么不是“Availability 是指所有的寫和讀都必須成功”? 要回答這個問題,我們可以仔細思考下“什么是成功”。“成功”必須要相對於某個參照而言,這里的參照就是 Consistency。
4.3 兩種重要的分布式場景
關於對CAP理論中一致性C的理解,除了上述數據副本之間的讀寫一致性以外,分布式環境中還有兩種非常重要的場景,如果不對它們進行認識與討論,就永遠無法全面地理解CAP,當然也就無法根據CAP做出正確的解釋。
1.分布式環境中的事務場景
我們知道,在關系型數據庫的事務操作遵循ACID原則,其中的一致性C,主要是指一個事務中相關聯的數據在事務操作結束后是一致的。所謂ACID原則,是指在寫入/異動資料的過程中,為保證交易正確可靠所必須具備的四個特性:即原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)和持久性(Durability)。
例如銀行的一個存款交易事務,將導致交易流水表增加一條記錄。同時,必須導致賬戶表余額發生變化,這兩個操作必須是一個事務中全部完成,保證相關數據的一致性。而前文解釋的CAP理論中的C是指對一個數據多個備份的讀寫一致性。表面上看,這兩者不是一回事,但實際上,卻是本質基本相同的事物:數據請求會等待多個相關數據操作全部完成才返回。對分布式系統來講,這就是我們通常所說的分布式事務問題。
眾所周知,分布式事務一般采用兩階段提交策略來實現,這是一個非常耗時的復雜過程,會嚴重影響系統效率,在實踐中我們盡量避免使用它。在實踐過程中,如果我們為了擴展數據容量將數據分布式存儲,而事務的要求又完全不能降低。那么,系統的可用性一定會大大降低,在現實中我們一般都采用對這些數據不分散存儲的策略。
當然,我們也可以說,最常使用的關系型數據庫,因為這個原因,擴展性(分區可容忍性P)受到了限制,這是完全符合CAP理論的。但同時我們應該意識到,這對NoSQL數據庫也是一樣的。如果NoSQL數據庫也要求嚴格的分布式事務功能,情況並不會比關系型數據庫好多少。只是在NoSQL的設計中,我們往往會弱化甚至去除事務的功能,該問題才表現得不那么明顯而已。
因此,在擴展性問題上,如果要說關系型數據庫是為了保證C、A而犧牲P,在盡量避免分布式事務這一點上來看,應該是正確的。也就是說:關系型數據庫應該具有強大的事務功能,如果分區擴展,可用性就會降低;而NoSQL數據庫干脆弱化甚至去除了事務功能,因此,分區的可擴展性就大大增加了。
2.分布式環境中的關聯場景
初看起來,關系型數據庫中常用的多表關聯操作與CAP理論就更加不沾邊了。但仔細考慮,也可以用它來解釋數據庫分區擴展對關聯所帶來的影響。對一個數據庫來講,采用了分區擴展策略來擴充容量,數據分散存儲了,很顯然多表關聯的性能就會下降,因為我們必須在網絡上進行大量的數據遷移操作,這與CAP理論中數據副本之間的同步操作本質上也是相同的。
因此,如果要保證系統的高可用性,需要同時實現強大的多表關系操作的關系型數據庫在分區可擴展性上就遇到了極大的限制(即使是那些采用了各種優秀解決方案的MPP架構的關系型數據庫,如TeraData,Netezza等,其水平可擴展性也是遠遠不如NoSQL數據庫的),而NoSQL數據庫則干脆在設計上弱化甚至去除了多表關聯操作。那么,從這一點上來理解"NoSQL數據庫是為了保證A與P,而犧牲C"的說法,也是可以講得通的。當然,我們應該理解,關聯問題在很多情況下不是並行處理的優點所在,這在很大程度上與Amdahl定律相符合。
所以,從事務與關聯的角度來看關系型數據庫的分區可擴展性為什么受限的原因是最為清楚的。而NoSQL數據庫也正是因為弱化,甚至去除了像事務與關聯(全面地講,其實還有索引等特性)等在分布式環境中會嚴重影響系統可用性的功能,才獲得了更好的水平可擴展性。
那么,如果將事務與關聯也納入CAP理論中一致性C的范疇的話,問題就很清楚了:關於“關系型數據庫為了保證一致性C與可用性A,而不得不犧牲分區可容忍性P”的說法便是正確的了。但關於"NoSQL選擇了C與P,或者A與P"的說法則是錯誤的,所有的NoSQL數據庫在設計策略的大方向上都是選擇了A與P(雖然對同一數據多個副本的讀寫一致性問題的設計各有不同),從來沒有完全選擇C與P的情況存在。
現在看來,如果理解CAP理論只是指多個數據副本之間讀寫一致性的問題,那么它對關系型數據庫與NoSQL數據庫來講是完全一樣的,它只是運行在分布式環境中的數據管理設施在設計讀寫一致性問題時需要遵循的一個原則而已,卻並不是NoSQL數據庫具有優秀的水平可擴展性的真正原因。而如果將CAP理論中的一致性C理解為讀寫一致性、事務與關聯操作的綜合,則可以認為關系型數據庫選擇了C與A,而NoSQL數據庫則全都是選擇了A與P,但並沒有選擇C與P的情況存在。
五.一致性分類
對於分布式數據系統,分區容忍性是基本要求,否則就失去了價值。因此設計分布式數據系統,就是在一致性和可用性之間取一個平衡。對於大多數WEB應用,其實並不需要強一致性,因此犧牲一致性而換取高可用性,是多數分布式數據庫產品的方向。
當然,犧牲一致性,並不是完全不管數據的一致性,否則數據是混亂的,那么系統可用性再高分布式再好也沒有了價值。犧牲一致性,只是不再要求關系型數據庫中的強一致性,而是只要系統能達到最終一致性即可,考慮到客戶體驗,這個最終一致的時間窗口,要盡可能的對用戶透明,也就是需要保障“用戶感知到的一致性”。通常是通過數據的多份異步復制來實現系統的高可用和數據的最終一致性的,“用戶感知到的一致性”的時間窗口則取決於數據復制到一致狀態的時間。
對於一致性,可以分為從客戶端和服務端兩個不同的視角。從客戶端來看,一致性主要指的是多並發訪問時更新過的數據如何獲取的問題。從服務端來看,則是更新如何復制分布到整個系統,以保證數據最終一致。一致性是因為有並發讀寫才有的問題,因此在理解一致性的問題時,一定要注意結合考慮並發讀寫的場景。
5.1 客戶端角度
從客戶端角度,多進程並發訪問時,更新過的數據在不同進程如何獲取的不同策略,決定了不同的一致性。對於關系型數據庫, 要求更新過的數據能被后續的訪問都能看到,這是強一致性。如果能容忍后續的部分或者全部訪問不到,則是弱一致性。如果經過一段時間后要求能訪問到更新后的數據,則是最終一致性。
在MongoDB中可以通過配置讓復制集成員內部支持強一致性,這時可以設置一個寫成功數,只有寫操作成功樹滿足設定的值時才會向客戶端返回結果。
最終一致性根據更新數據后各進程訪問到數據的時間和方式的不同,又可以區分為:因果一致性(CAUSAL CONSISTENCY),如果進程A通知進程B它已更新了一個數據項,那么進程B的后續訪問將返回更新后的值,且一次寫入將保證取代前一次寫入。與進程A無因果關系的進程C的訪問遵守一般的最終一致性規則。讀己之所寫(READ-YOUR-WRITES)一致性,當進程A自己更新一個數據項之后,它總是訪問到更新過的值,絕不會看到舊值。這是因果一致性模型的一個特例。會話(SESSION)一致性,這是上一個模型的實用版本,它把訪問存儲系統的進程放到會話的上下文中。只要會話還存在,系統就保證“讀己之所寫”一致性。如果由於某些失敗情形令會話終止,就要建立新的會話,而且系統的保證不會延續到新的會話。單調(MONOTONIC)讀一致性,如果進程已經看到過數據對象的某個值,那么任何后續訪問都不會返回在那個值之前的值。單調寫一致性,系統保證來自同一個進程的寫操作順序執行。要是系統不能保證這種程度的一致性,就非常難以編程了。
上述最終一致性的不同方式可以進行組合,例如單調讀一致性和讀己之所寫一致性就可以組合實現。並且從實踐的角度來看,這兩者的組合,讀取自己更新的數據,和一旦讀取到最新的版本不會再讀取舊版本,對於此架構上的程序開發來說,會少很多額外的煩惱。
5.2 服務端角度
從服務端角度,如何盡快將更新后的數據分布到整個系統,降低達到最終一致性的時間窗口,是提高系統的可用度和用戶體驗非常重要的方面。對於分布式數據系統:N — 數據復制的份數,W — 更新數據是需要保證寫完成的節點數,R — 讀取數據的時候需要讀取的節點數,如果W+R>N,寫的節點和讀的節點重疊,則是強一致性。例如對於典型的一主一備同步復制的關系型數據庫,N=2,W=2,R=1,則不管讀的是主庫還是備庫的數據,都是一致的。如果W+R<=N,則是弱一致性。例如對於一主一備異步復制的關系型數據庫,N=2,W=1,R=1,則如果讀的是備庫,就可能無法讀取主庫已經更新過的數據,所以是弱一致性。
對於分布式系統,為了保證高可用性,一般設置N>=3。不同的N,W,R組合,是在可用性和一致性之間取一個平衡,以適應不同的應用場景。如果N=W,R=1,任何一個寫節點失效,都會導致寫失敗,因此可用性會降低,但是由於數據分布的N個節點是同步寫入的,因此可以保證強一致性。如果N=R,W=1,只需要一個節點寫入成功即可,寫性能和可用性都比較高。但是讀取其他節點的進程可能不能獲取更新后的數據,因此是弱一致性。這種情況下,如果W<(N+1)/2,並且寫入的節點不重疊的話,則會存在寫沖突。
六.傳統數據庫與NoSQL數據庫
傳統的關系型數據庫在功能支持上通常很寬泛,從簡單的鍵值查詢,到復雜的多表聯合查詢再到事務機制的支持。而與之不同的是,NoSQL系統通常注重性能和擴展性,而非事務機制(事務就是強一致性的體現)。
傳統的SQL數據庫的事務通常都是支持ACID的強事務機制。A代表原子性,即在事務中執行多個操作是原子性的,要么事務中的操作全部執行,要么一個都不執行;C代表一致性,即保證進行事務的過程中整個數據加的狀態是一致的,不會出現數據花掉的情況;I代表隔離性,即兩個事務不會相互影響,覆蓋彼此數據等;D表示持久化,即事務一量完成,那么數據應該是被寫到安全的,持久化存儲的設備上(比如磁盤)。
NoSQL系統僅提供對行級別的原子性保證,也就是說同時對同一個Key下的數據進行的兩個操作,在實際執行的時候是會串行的執行,保證了每一個Key-Value對不會被破壞。例如MongoDB數據庫,它是不支持事務機制的,同時也不提倡多表關聯的復雜模式設計,它只保證對單個文檔(相當於關系數據庫中的記錄)讀寫的原子性。
補充: MPP架構介紹 MPP (Massively Parallel Processing),大規模並行處理系統,這樣的系統是由許多松耦合的處理單元組成的,要注意的是這里指的是處理單元而不是處理器。每個單元內的CPU都有自己私有的資源,如總線,內存,硬盤等。在每個單元內都有操作系統和管理數據庫的實例復本。這種結構最大的特點在於不共享資源。
七.戰勝CAP
核心內容就是放松Gilbert和Lynch證明中的限制:“系統必須同時達到CAP三個屬性”,放松到“系統可以不同時達到CAP,而是分時達到”。
CAP理論被很多人拿來作為分布式系統設計的金律,然而感覺大家對CAP這三個屬性的認識卻存在不少誤區。從CAP的證明中可以看出來,這個理論的成立是需要很明確的對C、A、P三個概念進行界定的前提下的。在本文中筆者希望可以對論文和一些參考資料進行總結並附帶一些思考
CAP理論的表述很好地服務了它的目的,即開闊設計師的思路,在多樣化的取舍方案下設計出多樣化的系統。在過去的十幾年里確實涌現了不計其數的新系統,也隨之在數據一致性和可用性的相對關系上產生了相當多的爭論。“三選二”的公式一直存在着誤導性,它會過分簡單化各性質之間的相互關系。現在我們有必要辨析其中的細節。實際上只有“在分區存在的前提下呈現完美的數據一致性和可用性”這種很少見的情況是CAP理論不允許出現的。
雖然設計師仍然需要在分區的前提下對數據一致性和可用性做取舍,但具體如何處理分區和恢復一致性,這里面有不計其數的變通方案和靈活度。當代CAP實踐應將目標定為針對具體的應用,在合理范圍內最大化數據一致性和可用性的“合力”。這樣的思路延伸為如何規划分區期間的操作和分區之后的恢復,從而啟發設計師加深對CAP的認識,突破過去由於CAP理論的表述而產生的思維局限。
7.1 為什么“三選二”公式有誤導性
理解CAP理論的最簡單方式是想象兩個節點分處分區兩側。允許至少一個節點更新狀態會導致數據不一致,即喪失了C性質。如果為了保證數據一致性,將分區一側的節點設置為不可用,那么又喪失了A性質。除非兩個節點可以互相通信,才能既保證C又保證A,這又會導致喪失P性質。一般來說跨區域的系統,設計師無法舍棄P性質,那么就只能在數據一致性和可用性上做一個艱難選擇。不確切地說,NoSQL運動的主題其實是創造各種可用性優先、數據一致性其次的方案;而傳統數據庫堅守ACID特性(原子性、一致性、隔離性、持久性),做的是相反的事情。下文“ACID、BASE、CAP”小節詳細說明了它們的差異。
“三選二”的觀點在幾個方面起了誤導作用,詳見下文“CAP之惑”小節的解釋。首先,由於分區很少發生,那么在系統不存在分區的情況下沒什么理由犧牲C或A。其次,C與A之間的取舍可以在同一系統內以非常細小的粒度反復發生,而每一次的決策可能因為具體的操作,乃至因為牽涉到特定的數據或用戶而有所不同。最后,這三種性質都可以在程度上衡量,並不是非黑即白的有或無。可用性顯然是在0%到100%之間連續變化的,一致性分很多級別,連分區也可以細分為不同含義,如系統內的不同部分對於是否存在分區可以有不一樣的認知。
要探索這些細微的差別,就要突破傳統的分區處理方式,而這是一項根本性的挑戰。因為分區很少出現,CAP在大多數時候允許完美的C和A。但當分區存在或可感知其影響的情況下,就要預備一種策略去探知分區並顯式處理其影響。這樣的策略應分為三個步驟:探知分區發生,進入顯式的分區模式以限制某些操作,啟動恢復過程以恢復數據一致性並補償分區期間發生的錯誤。
7.2 解決CAP
根據一些專家的分析,CAP並不是一個嚴謹的定律,並不是犧牲了Consistency,就一定能同時獲得Availability和Partition Tolerance。還有一個很重要的因素是Latency,在CAP中並沒有體現。在現在NoSQL以及其他一些大規模設計時,A和P並不是犧牲C或部分犧牲C的借口,因為即使犧牲了C,也不一定A和P,並且C不一定必須要犧牲。
淘寶一天就處理了1億零580萬,而12306一天處理的交易僅僅166萬條 ,如果從並發性上來說,淘寶的並發量遠比12306大,但天貓的商品信息,促銷數據都可以做緩存,做CDN,而12306的“商品”是一個個座位,這些座位必須通過后端數據庫即時查詢出來,狀態的一致性要求很高。
從這點上看,12306的商品信息很難利用到緩存,因此12306查看“商品”的代價是比較大的,涉及到一系列的后端數據庫操作,從這個角度講,12306的復雜度是高於天貓的。 淘寶的商品相對獨立,而12306商品之間的關聯性很大,由於CAP定律限制,如果其商品的一致性要求過高,必然對可用性和分區容錯性造成影響。
因此,業務設計上,如果找到一條降低一致性要求時,還能保證業務的正確性的業務分拆之路。舉個例子,火車票查詢時,不要顯示多少張,而是顯示“有”或“無”,或者顯示>100張,50~100,小於50等,這樣就可以減小狀態的更新頻率,充分使用緩存數據。
CAP 理論說在一個系統中對某個數據不存在一個算法同時滿足 Consistency, Availability, Partition-tolerance。注意,這里邊最重要和最容易被人忽視的是限定詞“對某個數據不存在一個算法”。這就是說在一個系統中,可以對某些數據做到 CP, 對另一些數據做到 AP,就算是對同一個數據,調用者可以指定不同的算法,某些算法可以做到 CP,某些算法可以做到 AP。
7.3 做到兩項
要做到 CP, 系統可以把這個數據只放在一個節點上,其他節點收到請求后向這個節點讀或寫數據,並返回結果。很顯然,串行化是保證的。但是如果報文可以任意丟失的話,接受請求的節點就可能永遠不返回結果。
要做到 CA, 一個現實的例子就是單點的數據庫。你可能會疑惑“數據庫也不是 100% 可用的呀?” 要回答這個疑惑,注意上面說的故障模型和 availability 的定義就可以了。
要做到 AP, 系統只要每次對寫都返回成功,對讀都返回固定的某個值就可以了。
如果我們到這里就覺得已近掌握好 CAP 理論了,那么就相當於剛把橘子剝開,就把它扔了。
CAP 理論更重要的一個結果是, 在 Partial Synchronous System (半同步系統) 中,一個弱化的 CAP 是能達到的:對所有的數據訪問,總返回一個結果 * 如果期間沒有報文丟失,那么返回一個滿足 consistency 要求的結果。
這里的半同步系統指每個節點存在一個時鍾,這些時鍾不需要同步,但是按照相同的速率流逝。更通俗的來說,就是一個能夠實現超時機制的系統。
舉個例子,系統可以把這個數據只放在一個節點上,其他節點收到請求后向這個節點讀或寫數據,並設置一個定時器,如果超時前得到結果,那么返回這個結果,否則返回失敗。更進一步的,也是最重要的,實現一個滿足最終一致性 (Eventually Consistency) 和 AP 的系統是可行的。 現實中的一個例子是 Cassandra 系統。
而對於分布式數據系統,分區容忍性是基本要求,否則就失去了價值。因此設計分布式數據系統,就是在一致性和可用性之間取一個平衡。對於大多數WEB應用,其實並不需要強一致性,因此犧牲一致性而換取高可用性,是多數分布式數據庫產品的方向。 當然,犧牲一致性,並不是完全不管數據的一致性,否則數據是混亂的,那么系統可用性再高分布式再好也沒有了價值。犧牲一致性,只是不再要求關系型數據庫中的強一致性,而是只要系統能達到最終一致性即可,考慮到客戶體驗,這個最終一致的時間窗口,要盡可能的對用戶透明,也就是需要保障“用戶感知到的一致性”。通常是通過數據的多份異步復制來實現系統的高可用和數據的最終一致性的,“用戶感知到的一致性”的時間窗口則取決於數據復制到一致狀態的時間。
最終一致性(EVENTUALLY CONSISTENT) 對於一致性,可以分為從客戶端和服務端兩個不同的視角。從客戶端來看,一致性主要指的是多並發訪問時更新過的數據如何獲取的問題。從服務端來看,則是更新如何復制分布到整個系統,以保證數據最終一致。一致性是因為有並發讀寫才有的問題,因此在理解一致性的問題時,一定要注意結合考慮並發讀寫的場景。 從客戶端角度,多進程並發訪問時,更新過的數據在不同進程如何獲取的不同策略,決定了不同的一致性。對於關系型數據庫,要求更新過的數據能被后續的訪問都能看到,這是強一致性。如果能容忍后續的部分或者全部訪問不到,則是弱一致性。如果經過一段時間后要求能訪問到更新后的數據,則是最終一致性。 最終一致性根據更新數據后各進程訪問到數據的時間和方式的不同,又可以區分為: 因果一致性(CAUSAL CONSISTENCY)
如果進程A通知進程B它已更新了一個數據項,那么進程B的后續訪問將返回更新后的值,且一次寫入將保證取代前一次寫入。與進程A無因果關系的進程C的訪問遵守一般的最終一致性規則。“讀己之所寫(READ-YOUR-WRITES)”一致性。當進程A自己更新一個數據項之后,它總是訪問到更新過的值,絕不會看到舊值。這是因果一致性模型的一個特例。會話(SESSION)一致性。這是上一個模型的實用版本,它把訪問存儲系統的進程放到會話的上下文中。只要會話還存在,系統就保證“讀己之所寫”一致性。如果由於某些失敗情形令會話終止,就要建立新的會話,而且系統的保證不會延續到新的會話。單調(MONOTONIC)讀一致性。如果進程已經看到過數據對象的某個值,那么任何后續訪問都不會返回在那個值之前的值。單調寫一致性。系統保證來自同一個進程的寫操作順序執行。要是系統不能保證這種程度的一致性,就非常難以編程了。上述最終一致性的不同方式可以進行組合,例如單調讀一致性和讀己之所寫一致性就可以組合實現。並且從實踐的角度來看,這兩者的組合,讀取自己更新的數據,和一旦讀取到最新的版本不會再讀取舊版本,對於此架構上的程序開發來說,會少很多額外的煩惱。 從服務端角度,如何盡快將更新后的數據分布到整個系統,降低達到最終一致性的時間窗口,是提高系統的可用度和用戶體驗非常重要的方面。
對於分布式數據系統: N — 數據復制的份數,W — 更新數據是需要保證寫完成的節點數,R — 讀取數據的時候需要讀取的節點數如果W+R>N,寫的節點和讀的節點重疊,則是強一致性。例如對於典型的一主一備同步復制的關系型數據庫,N=2,W=2,R=1,則不管讀的是主庫還是備庫的數據,都是一致的。 如果W+R<=N,則是弱一致性。例如對於一主一備異步復制的關系型數據庫,N=2,W=1,R=1,則如果讀的是備庫,就可能無法讀取主庫已經更新過的數據,所以是弱一致性。 對於分布式系統,為了保證高可用性,一般設置N>=3。不同的N,W,R組合,是在可用性和一致性之間取一個平衡,以適應不同的應用場景。 如果N=W,R=1,任何一個寫節點失效,都會導致寫失敗,因此可用性會降低,但是由於數據分布的N個節點是同步寫入的,因此可以保證強一致性。如果N=R,W=1,只需要一個節點寫入成功即可,寫性能和可用性都比較高。但是讀取其他節點的進程可能不能獲取更新后的數據,因此是弱一致性。這種情況下,如果W<(N+1)/2,並且寫入的節點不重疊的話,則會存在寫沖突。
八.參考文獻
[1]http://www.infoq.com/cn/articles/cap-twelve-years-later-how-the-rules-have-changed/
[2]http://blog.csdn.net/it_man/article/details/8574201
[3]http://www.cnblogs.com/mmjx/archive/2011/12/19/2290540.html
[4]http://blog.csdn.net/zhangzhebjut/article/details/22977977