任老師第一節主要講了分佈式系統實現時候面臨的八個問題,佈置的做業就是這個,查詢CAP理論。html
筆者初次接觸分佈式,因此本文主要是一個彙總。算法
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定律說的是在一個分佈式計算機系統中,一致性,可用性和分區容錯性這三種保證沒法同時獲得知足,最多知足兩個。
強一致性:系統在執行過某項操做後仍然處於一致的狀態。在分佈式系統中,更新操做執行成功後全部的用戶都應該讀到最新的值,這樣的系統被認爲是具備強一致性的。 等同於全部節點訪問同一份最新的數據副本;
All clients always have the same view of the data。
可用性:每個操做老是可以在必定的時間內返回結果,這裏須要注意的是"必定時間內"和"返回結果"。必定時間指的是,在能夠容忍的範圍內返回結果,結果能夠是成功或者失敗。 對數據更新具有高可用性(A);
Each client can alwa read and write。
分區容錯性:理解爲在存在網絡分區的狀況下,仍然能夠接受請求(知足一致性和可用性)。這裏的網絡分區是指因爲某種緣由,網絡被分紅若干個孤立的區域,而區域之間互不相通。還有一些人將分區容錯性理解爲系統對節點動態加入和離開的能力,由於節點的加入和離開能夠認爲是集羣內部的網絡分區。
Partition Tolerance的意思是,在網絡中斷,消息丟失的狀況下,系統照樣可以工做。 以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇
2.4 放棄C.A.P
放棄P:若是想避免分區容錯性問題的發生,一種作法是將全部的數據(與事務相關的)都放在一臺機器上。雖然沒法100%保證系統不會出錯,但不會碰到由分區帶來的負面效果。固然這個選擇會嚴重的影響系統的擴展性。
放棄A:相對於放棄「分區容錯性「來講,其反面就是放棄可用性。一旦遇到分區容錯故障,那麼受到影響的服務須要等待必定的時間,所以在等待期間系統沒法對外提供服務。
放棄C:這裏所說的放棄一致性,並非徹底放棄數據一致性,而是放棄數據的強一致性,而保留數據的最終一致性。以網絡購物爲例,對只剩下一件庫存的商品,若是同時接受到了兩份訂單,那麼較晚的訂單將被告知商品告罄。
一致性與可用性的決擇: 而CAP理論就是說在分佈式存儲系統中,最多隻能實現上面的兩點。而因爲當前的網絡硬件確定 會出現延遲丟包等問題,因此分區容忍性是咱們必須須要實現的。因此咱們只能在一致性和可用 性之間進行權衡。
CAP的證實基於異步網絡,異步網絡也是反映了真實網絡中狀況的模型。真實的網絡系統中,節點之間不可能保持同步,即使是時鐘也不可能保持同步,全部的節點依靠得到的消息來進行本地計算和通信。這個概念實際上是至關強的,意味着任何超時判斷也是不可能的,由於沒有共同的時間標準。以後咱們會擴展CAP的證實到弱一點的異步網絡中,這個網絡中時鐘不徹底一致,可是時鐘運行的步調是一致的,這種系統是容許節點作超時判斷的。
CAP的證實很簡單,假設兩個節點集{G1, G2},因爲網絡分片致使G1和G2之間全部的通信都斷開了,若是在G1中寫,在G2中讀剛寫的數據, G2中返回的值不可能G1中的寫值。因爲A的要求,G2必定要返回此次讀請求,因爲P的存在,致使C必定是不可知足的。
目前流行的、對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數據庫、關係型數據庫,乃至一切分佈式系統在設計數據多個副本之間讀寫一致性問題時須要遵循的共同原則。
要真正理解 CAP 理論必需要讀懂它的形式化描述。 形式化描述中最重要的莫過於對 Consistency, Availability, Partition-tolerance 的準肯定義。
Consistency (一致性) 實際上等同於系統領域的 before-or-after atomicity 這個術語,或者等同於 linearizable (可串行化) 這個術語。具體來講,系統中對一個數據的讀和寫雖然包含多個子步驟而且會持續一段時間才能執行完,可是在調用者看來,讀操做和寫操做都必須是單個的即時完成的操做,不存在重疊。對一個寫操做,若是系統返回了成功,那麼以後到達的讀請求都必須讀到這個新的數據;若是系統返回失敗,那麼全部的讀,不管是以後發起的,仍是和寫同時發起的,都不能讀到這個數據。
要說清楚 Availability 和 Partition-tolerance 必需要定義好系統的故障模型。在形式化證實中,系統包含多個節點,每一個節點能夠接收讀和寫的請求,返回成功或失敗,對讀還要返回一個數據。和調用者之間的鏈接是不會中斷的,系統的節點也不會失效,惟一的故障就是報文的丟失。 Partition-tolerance 指系統中會任意的丟失報文(這和「最終會有一個報文會到達」是相對的)。 Availability 是指全部的讀和寫都必需要能終止。
注: 「Availability 是指全部的讀和寫都必需要能終止」 這句話聽上去很奇怪,爲何不是「Availability 是指全部的寫和讀都必須成功」? 要回答這個問題,咱們能夠仔細思考下「什麼是成功」。「成功」必需要相對於某個參照而言,這裏的參照就是 Consistency。
關於對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應用,其實並不須要強一致性,所以犧牲一致性而換取高可用性,是多數分佈式數據庫產品的方向。
固然,犧牲一致性,並非徹底無論數據的一致性,不然數據是混亂的,那麼系統可用性再高分佈式再好也沒有了價值。犧牲一致性,只是再也不要求關係型數據庫中的強一致性,而是隻要系統能達到最終一致性便可,考慮到客戶體驗,這個最終一致的時間窗口,要儘量的對用戶透明,也就是須要保障「用戶感知到的一致性」。一般是經過數據的多份異步複製來實現系統的高可用和數據的最終一致性的,「用戶感知到的一致性」的時間窗口則取決於數據複製到一致狀態的時間。
對於一致性,能夠分爲從客戶端和服務端兩個不一樣的視角。從客戶端來看,一致性主要指的是多併發訪問時更新過的數據如何獲取的問題。從服務端來看,則是更新如何複製分佈到整個系統,以保證數據最終一致。一致性是由於有併發讀寫纔有的問題,所以在理解一致性的問題時,必定要注意結合考慮併發讀寫的場景。
從客戶端角度,多進程併發訪問時,更新過的數據在不一樣進程如何獲取的不一樣策略,決定了不一樣的一致性。對於關係型數據庫, 要求更新過的數據能被後續的訪問都能看到,這是強一致性。若是能容忍後續的部分或者所有訪問不到,則是弱一致性。若是通過一段時間後要求能訪問到更新後的數據,則是最終一致性。
在MongoDB中能夠經過配置讓複製集成員內部支持強一致性,這時能夠設置一個寫成功數,只有寫操做成功樹知足設定的值時纔會向客戶端返回結果。
最終一致性根據更新數據後各進程訪問到數據的時間和方式的不一樣,又能夠區分爲:因果一致性(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,而且寫入的節點不重疊的話,則會存在寫衝突。
傳統的關係型數據庫在功能支持上一般很寬泛,從簡單的鍵值查詢,到複雜的多表聯合查詢再到事務機制的支持。而與之不一樣的是,NoSQL系統一般注重性能和擴展性,而非事務機制(事務就是強一致性的體現)。
傳統的SQL數據庫的事務一般都是支持ACID的強事務機制。A表明原子性,即在事務中執行多個操做是原子性的,要麼事務中的操做所有執行,要麼一個都不執行;C表明一致性,即保證進行事務的過程當中整個數據加的狀態是一致的,不會出現數據花掉的狀況;I表明隔離性,即兩個事務不會相互影響,覆蓋彼此數據等;D表示持久化,即事務一量完成,那麼數據應該是被寫到安全的,持久化存儲的設備上(好比磁盤)。
NoSQL系統僅提供對行級別的原子性保證,也就是說同時對同一個Key下的數據進行的兩個操做,在實際執行的時候是會串行的執行,保證了每個Key-Value對不會被破壞。例如MongoDB數據庫,它是不支持事務機制的,同時也不提倡多表關聯的複雜模式設計,它只保證對單個文檔(至關於關係數據庫中的記錄)讀寫的原子性。
補充: MPP架構介紹 MPP (Massively Parallel Processing),大規模並行處理系統,這樣的系統是由許多鬆耦合的處理單元組成的,要注意的是這裏指的是處理單元而不是處理器。每一個單元內的CPU都有本身私有的資源,如總線,內存,硬盤等。在每一個單元內都有操做系統和管理數據庫的實例複本。這種結構最大的特色在於不共享資源。
核心內容就是放鬆Gilbert和Lynch證實中的限制:「系統必須同時達到CAP三個屬性」,放鬆到「系統能夠不一樣時達到CAP,而是分時達到」。
CAP理論被不少人拿來做爲分佈式系統設計的金律,然而感受你們對CAP這三個屬性的認識卻存在很多誤區。從CAP的證實中能夠看出來,這個理論的成立是須要很明確的對C、A、P三個概念進行界定的前提下的。在本文中筆者但願能夠對論文和一些參考資料進行總結並附帶一些思考
CAP理論的表述很好地服務了它的目的,即開闊設計師的思路,在多樣化的取捨方案下設計出多樣化的系統。在過去的十幾年裏確實涌現了不可勝數的新系統,也隨之在數據一致性和可用性的相對關係上產生了至關多的爭論。「三選二」的公式一直存在着誤導性,它會過度簡單化各性質之間的相互關係。如今咱們有必要辨析其中的細節。實際上只有「在分區存在的前提下呈現完美的數據一致性和可用性」這種不多見的狀況是CAP理論不容許出現的。
雖然設計師仍然須要在分區的前提下對數據一致性和可用性作取捨,但具體如何處理分區和恢復一致性,這裏面有不可勝數的變通方案和靈活度。當代CAP實踐應將目標定爲針對具體的應用,在合理範圍內最大化數據一致性和可用性的「協力」。這樣的思路延伸爲如何規劃分區期間的操做和分區以後的恢復,從而啓發設計師加深對CAP的認識,突破過去因爲CAP理論的表述而產生的思惟侷限。
理解CAP理論的最簡單方式是想象兩個節點分處分區兩側。容許至少一個節點更新狀態會致使數據不一致,即喪失了C性質。若是爲了保證數據一致性,將分區一側的節點設置爲不可用,那麼又喪失了A性質。除非兩個節點能夠互相通訊,才能既保證C又保證A,這又會致使喪失P性質。通常來講跨區域的系統,設計師沒法捨棄P性質,那麼就只能在數據一致性和可用性上作一個艱難選擇。不確切地說,NoSQL運動的主題實際上是創造各類可用性優先、數據一致性其次的方案;而傳統數據庫堅守ACID特性(原子性、一致性、隔離性、持久性),作的是相反的事情。下文「ACID、BASE、CAP」小節詳細說明了它們的差別。
「三選二」的觀點在幾個方面起了誤導做用,詳見下文「CAP之惑」小節的解釋。首先,因爲分區不多發生,那麼在系統不存在分區的狀況下沒什麼理由犧牲C或A。其次,C與A之間的取捨能夠在同一系統內以很是細小的粒度反覆發生,而每一次的決策可能由於具體的操做,乃至由於牽涉到特定的數據或用戶而有所不一樣。最後,這三種性質均可以在程度上衡量,並非非黑即白的有或無。可用性顯然是在0%到100%之間連續變化的,一致性分不少級別,連分區也能夠細分爲不一樣含義,如系統內的不一樣部分對因而否存在分區能夠有不同的認知。
要探索這些細微的差異,就要突破傳統的分區處理方式,而這是一項根本性的挑戰。由於分區不多出現,CAP在大多數時候容許完美的C和A。但當分區存在或可感知其影響的狀況下,就要預備一種策略去探知分區並顯式處理其影響。這樣的策略應分爲三個步驟:探知分區發生,進入顯式的分區模式以限制某些操做,啓動恢復過程以恢復數據一致性並補償分區期間發生的錯誤。
根據一些專家的分析,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。
要作到 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