看完這篇,保證讓你真正明白:分佈式系統的CAP理論、CAP如何三選二

引言

CAP 理論,相信不少人都聽過,它是指:程序員

一個分佈式系統最多隻能同時知足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。面試

爲何要理解 CAP 理論?我能說出不少理由來。若是是在職場上,也許最合適的理由是,當領導給出的任務不靠譜時,咱們能夠依據 CAP 去否決它。服務器

好比,有這麼一個任務,給你定了三大目標:網絡

  1. 既要提高系統的可用性
  2. 又要保證數據的實時可見
  3. 還有提高系統的容錯能力

看到「既要、又要、還要」,是否是想到了阿里……多線程

OK,若是你深入理解了 CAP,你會發現完成這個任務是不可能的。可是,若是你不理解 CAP,而後又拍了胸脯保證完成任務,很差意思,職場是不須要眼淚和後悔的。架構

有點跑題了,書歸正傳。CAP 理論是分佈式設計中最基礎最重要的理論,不懂它,你可能連分析一套分佈式系統的核心設計理念都作不到。異步

關於 CAP 爲什麼你讀了那麼多文章都仍是搞不明白呢?由於 CAP 理論來自學術界,而解讀 CAP 理論的人嘗試用工程師的方式去闡述它,這自己就有了問題。分佈式

CAP 自己基於狀態,基於瞬態,是一個描述性的理論,它並不解決工程問題。可是,不少工程師卻老是嘗試爲 CAP 作過多解讀。好比,非要說 CAP 理論只能適合某某場景,非要說 CAP 理論裏的一致性是很是強的一致性,把其和事務的一致性混爲一談。性能

因爲 CAP 是學術理論,並非工程理論,它會捨棄不少現實世界的現實問題。好比網絡的時長,好比節點內部的處理速度不一致,好比節點間存儲方式和速度的不一致。它說的一致性就是客戶端是否能拿到最新數據,它說的可用性就是容許客戶端拿不到最新數據。而這些東西被工程師們的過多腦補,致使了文章和文章說法不同,解析不同,闡述背景不同。學習

在今天這篇文章中,咱們只解釋和說明,不腦補,不過多從工程角度解讀,只說本質,只指核心,但願能真正說清楚、講明白 CAP 理論。望本文能達到這個目的。

接下來你看到文字,我前先後後寫了 10 天,已是這篇文章的第三版了,前兩版寫了一半都被我推翻重寫了,由於我本身看了都不滿意。

一方面是對本身知識掌握程度不滿意,本覺得本身明白 CAP 了,直到寫的時候,發現有些仍是拿不許。

另外一方面是不滿意本身的寫的太晦澀、太教科書,能把知識講的通俗易懂,纔是我但願的。

給你們看看文章上輩子的模樣。
在這裏插入圖片描述

1. CAP 的由來

要理解 CAP,首先咱們要清楚,爲什麼會有人提出 CAP?他提出 CAP 是爲了解決什麼問題?

時間回到 1985 年,彼時,後來證實了 CAP 理論的 Lynch 教授此時給當時的 IT 界來了一記驚雷:

她經過不可辯駁的證實告訴業界的工程師們,若是在一個不穩定(消息要麼亂序要麼丟了)的網絡環境裏(分佈式異步模型),想始終保持數據一致是不可能的。

這是個什麼概念呢?就是她打破了那些既想提供超高質量服務,又想提供超高性能服務的技術人員的幻想。

這本質是在告訴你們,在分佈式系統裏,須要妥協。

可是,如何妥協?分佈式系統裏到底應該怎麼權衡這種 trade-off?

咱們能夠想象一下,在 CAP 定理提出以前,沒有這些方向性的指引,在設計和實施分佈式系統時該有多麼混亂。一套分佈式系統是由多個模塊組成的,這些模塊自己可能由不一樣的開發人員去完成。然而,對於這些人,在公共層面,居然沒有一個原則去指導他們該怎麼完成這套功能。

好比,咱們在同步兩個節點的數據時,若是發生了錯誤,到底咱們應該怎麼作呢?若是沒有統一的標準和方向,那極可能在一套分佈式系統中的不一樣模塊,會出現不一樣的處理狀況。

假設一套系統,由 A、B 兩個模塊構成。

A 模塊的設計理念是:節點間出現了問題,它可能會選擇不斷的重試,一直等到節點通訊恢復。
在這裏插入圖片描述
而 B 的設計理念是:節點間出現了問題,它斷開就是了,可能最多就記錄下狀態,等之後處理。
在這裏插入圖片描述
但是,當 A、B 之間出現了通訊怎麼辦?那會出現 A 往 B 發請求,出問題會不斷重試。而 B 往 A 發請求,出問題則直接斷開的狀況。

固然,在後面咱們會說明,CAP 的理念在實際工程中,會容許這種不一致。但是,那種不一致是提早設計好和規劃好的,是根據實際數據的重要性和業務需求作的妥協,而不是這種混亂的妥協。

因此,IT 界的人們就一直在摸索,試圖找到一些綱領去指導分佈式系統的設計,這一找就找了 15 年。

2000 年時,Eric Brewer 教授在 PODC 會議上提出了 CAP 理論,可是因爲沒有被證實過,因此,當時只能被稱爲 CAP 猜測。這個猜測引發了巨大的反響,由於 CAP 很符合人們對設計綱領的預期。

在 2002 年後,通過 Seth Gilbert 和 Nancy Lynch 從理論上證實了 CAP 猜測後,CAP 理論正式成爲了分佈式系統理論的基石之一。

2. CAP 究竟是什麼

CAP 定理表達了一個分佈式系統裏不可能同時知足如下的三個特性:

2.1. C:數據一致性

什麼是數據一致性?咋一看真的很讓人糊塗,一致性是什麼?是指數據能一塊兒變化,是能讓數據整齊劃一。

那麼問題又來了,數據什麼時候會變化?數據怎麼才能被稱爲一塊兒變化?咱們如今來回答這些問題,當咱們搞清楚了這些問題,那麼對數據一致性就會有了清晰的理解。

首先第一個問題,數據什麼時候會一塊兒變化?

答案是:僅且僅當包含數據的服務,收到數據更新請求的時候,數據纔會發生變化。而數據更新請求則僅包括數據的增、刪、改這三種請求,而這三種請求又被統稱爲寫請求。因此,數據只有在寫請求的時候纔會發生變化。

那咱們來回答第二個問題,數據要怎麼樣才能被稱爲一塊兒變化了?即誰來判斷數據是最終變化了?是服務器對寫請求的返回結果嗎?告訴寫請求成功,數據就必定發生一致性變化了?

NO,數據發生變化是否一致是須要通過讀請求來作檢驗的。那麼讀請求判斷的依據是什麼呢?

假設,咱們的分佈式存儲系統有兩個節點,每一個節點都包含了一部分須要被變化的數據。若是通過一次寫請求後,兩個節點都發生了數據變化。而後,讀請求把這些變化後的數據都讀取到了,咱們就把此次數據修改稱爲數據發生了一致性變化。
在這裏插入圖片描述
可是,這還不是完整的一致性。由於系統不可能永久的正常運行下去。

若是系統內部發生了問題從而致使系統的節點沒法發生一致性變化會怎麼樣呢?當咱們這樣作的時候,就意味着想看到最新數據的讀請求們,極可能會看到舊數據,或者說獲取到不一樣版本的數據。此時,爲了保證分佈式系統對外的數據一致性,因而選擇不返回任何數據。
在這裏插入圖片描述
這裏須要注意一下,CAP 定理是在說在某種狀態下的選擇,和實際工程的理論是有差異的。上面描述的一致性和 ACID 事務中的一致性是兩回事。事務中的一致性包含了實際工程對狀態的後續處理。可是 CAP 定理並不涉及到狀態的後續處理,對於這些問題,後續出現了 BASE 理論等工程結論去處理,目前,只須要明白 CAP 定理主要描述的是狀態。

2.2. A:可用性

奧維德曾經說過:「行動被人們遺忘,結果卻將永存」。

這句話說明告終果的重要性,而可用性在 CAP 裏就是對結果的要求。它要求系統內的節點們接收到了不管是寫請求仍是讀請求,都要能處理並給迴響應結果。只是它有兩點必須知足的條件:

條件 1:返回結果必須在合理的時間之內,這個合理的時間是根據業務來定的。業務說必須 100 毫秒內返回,合理的時間就是 100 毫秒,須要 1 秒內返回,那就是 1 秒,若是業務定的 100 毫秒,結果卻在 1 秒才返回,那麼這個系統就不知足可用性。

條件 2:須要系統內能正常接收請求的全部節點都返回結果。這包含了兩重含義:

  1. 若是節點不能正常接收請求了,好比宕機了,系統崩潰了,而其餘節點依然能正常接收請求,那麼,咱們說系統依然是可用的,也就是說,部分宕機沒事兒,不影響可用性指標。

  2. 若是節點能正常接收請求,可是發現節點內部數據有問題,那麼也必須返回結果,哪怕返回的結果是有問題的。好比,系統有兩個節點,其中有一個節點數據是三天前的,另外一個節點是兩分鐘前的,若是,一個讀請求跑到了包含了三天前數據的那個節點上,抱歉,這個節點不能拒絕,必須返回這個三天前的數據,即便它可能不太合理。
    在這裏插入圖片描述

2.3. P:分區容忍性

分佈式的存儲系統會有不少的節點,這些節點都是經過網絡進行通訊。而網絡是不可靠的,當節點和節點之間的通訊出現了問題,此時,就稱當前的分佈式存儲系統出現了分區。可是,值得一提的是,分區並不必定是由網絡故障引發的,也多是由於機器故障。

好比,咱們的分佈式存儲系統有 A、B 兩個節點。那麼,當 A、B 之間因爲可能路由器、交換機等底層網絡設備出現了故障,A 和 B 通訊出現了問題,可是 A、B 依然都在運行,都在對外提供服務。這時候,就說 A 和 B 發生了分區。

還有一種狀況也會發生分區,當 A 出現了宕機,A 和 B 節點之間通訊也是出現了問題,那麼咱們也稱 A 和 B 發生了分區。

綜上,咱們能夠知道,只要在分佈式系統中,節點通訊出現了問題,那麼就出現了分區。
在這裏插入圖片描述
那麼,分區容忍性是指什麼? 它是說,若是出現了分區問題,咱們的分佈式存儲系統還須要繼續運行。不能由於出現了分區問題,整個分佈式節點所有就熄火了,罷工了,不作事情了。
在這裏插入圖片描述

3. CAP 怎麼選擇

咱們上面已經知道了,在設計分佈式系統時,架構師們在 C、A、P 這三種特性裏,只能選擇兩種。

可是,這道 CAP 的選擇題,就像別人在問你「小明的父親有三個孩子,老大叫大朗,老二叫二郎,請問老三叫什麼」同樣。在以分佈式存系統爲限定條件的 CAP 世界裏,P 是早已經肯定的答案,P 是必須的。

由於,在分佈式系統內,P 是必然的發生的,不選 P,一旦發生分區錯誤,整個分佈式系統就徹底沒法使用了,這是不符合實際須要的。因此,對於分佈式系統,咱們只能能考慮當發生分區錯誤時,如何選擇一致性和可用性。

而根據一致性和可用性的選擇不一樣,開源的分佈式系統每每又被分爲 CP 系統和 AP 系統。

當一套系統在發生分區故障後,客戶端的任何請求都被卡死或者超時,可是,系統的每一個節點老是會返回一致的數據,則這套系統就是 CP 系統,經典的好比 Zookeeper。

若是一套系統發生分區故障後,客戶端依然能夠訪問系統,可是獲取的數據有的是新的數據,有的仍是老數據,那麼這套系統就是 AP 系統,經典的好比 Eureka。

說了這麼多,其實 CAP 定理本質很簡單,它就是一種分佈式系統設計的不一樣理念歸納,包括它說的一致性,可用性和分區容錯性。這就相似一個大學的校訓,是極度概念化的東西。

因此,大白話來形容下 CAP 吧,CAP 就是告訴程序員們當分佈式系統出現內部問題了,你要作兩種選擇:

  • 要麼遷就外部服務,像外包公司。
  • 要麼讓外部服務遷就你,像銀行。

遷就外部服務就是咱們不能由於咱們本身的問題讓外部服務的業務運行受到影響,因此要優先可用性。而讓外部服務遷就咱們,就要優先一致性。

4. 對 CAP 的常見誤解

誤解一:分佈式系統由於 CAP 定理放棄了 C 或者 A 中的其中一個

不少人在沒有對 CAP 作深刻了解的狀況下,聽到不少人說分佈式系統必須在 CAP 三個特性裏選擇兩個,就以爲一套分佈式系統確定要麼只有可用性要麼只有一致性,不存在完整的可用性和一致性功能。

這種理解是大有問題的。由於,P 這種問題發生的機率很是低,因此:

當沒有出現分區問題的時候,系統就應該有完美的數據一致性和可用性。

你何時見過一個系統,當內部沒有問題的時候,會常常讓外部請求卡一下的?要麼就冷不丁的提供陳舊的老數據?那還能叫系統嗎?

誤解二:C 和 A 之間的選擇是針對整個分佈式系統的,只能總體考慮 C 和 A 之間的選擇

這個理解也是不對的。當分區發生的時候,其實對一致性和可用性的抉擇是局部性的,而不是針對整個系統的。

多是在一些子系統作一些抉擇,甚至極可能只須要對某個事件或者數據,作一致性和可用性的抉擇而已。

好比,當咱們作一套支付系統的時候,會員的財務相關像帳戶餘額,帳務流水是必須強一致性的。這時候,你就要考慮選 C。可是,會員的名字,會員的支付設置就沒必要考慮強一致性,能夠選擇可用性 A。

一套分佈式系統的運行,就像人生同樣,就是一次又一次的選擇。在不一樣階段,不一樣的時刻有不一樣的事件發生的時候,又怎麼可能會有徹底同樣的選擇呢?

誤解三:CAP 的三個特性只有是和否兩種極端選擇,而不是一個範圍

這種二元性的理解更是極其誤導人。

CAP 理論的三種特性不是 Boolean 類型的,不是一致和不一致,可用和不可用,分區和沒分區的這類二選一的選項。而是這三種特性都是範圍類型。

拿可用性來講,就像我從銀行取錢。當我目的是派發壓歲錢的時候,我極可能就想全要新票子,可是,新票子極可能就還得多一個步驟,就是須要拿舊票子去換一些新票,此時,我能夠多等會兒,能拿到新票子就好。而當個人目的就是作生活花銷的時候,票子是新是舊,我根本不那麼關心,快點拿到錢就行。這就是可用性的範圍需求之一,對時延性的要求。

再好比,分區容錯則因爲探測機制的問題,可能還得各節點搞投票去協商分區是否存在,當某一臺機器出現了問題,可能不影響業務的話,就會被機器投票認爲分區不存在。而後一直等到多數機器出現了問題,纔會投票確認出現了分區問題。這就好像新冠疫情,還會分低、中、高風險區呢,不是一出現通訊故障就都被邏輯認定爲分區問題。

5. CAP 理論的一些疑問

疑問一:在聽從 CAP 定理的系統中是否適合任意的寫請求

首先,在 CAP 定理中,關於一致性會有多種說法,可是總的來講,都是在描述數據最新版本的可見性。而這些可見性每每表明的是讀請求返回的數據的可見性。

那麼問題來了,當咱們要求讀數據的可見性的時候,對寫數據有什麼要求嗎?

好比,咱們系統有三個節點,一個客戶端給這個系統發了一個寫請求,要求系統寫入一個值爲 20 的數據。那麼,若是要知足 CAP 定理中的一致性,就須要在寫完 20 這個數據以後,當其餘客戶端請求讀取這個值爲 20 的數據以後,不管請求被轉發到系統中任何節點都能返回這個值。

這就要求寫入這個值爲 20 的寫請求必須成功寫到三個節點上,此時,系統就知足了寫一致性的。因此,咱們能夠說對於讀一致性的要求是同時約束了寫一致性的。
在這裏插入圖片描述
其次,在 CAP 定理中,可用性自己要求對讀、寫請求都要處理。若是咱們以可用性做爲標準的時候,在發生分區錯誤時,因爲咱們對讀請求並無強行要求返回徹底準確的數據,因此,可能在本次讀請求以前的最近一次寫請求多是部分失敗的。

一樣的例子,咱們的分佈式系統由三個節點組成,最近一次寫請求想把值爲 20 的數據寫到三個節點上。可是,因爲發生了分區問題,有一個節點通訊故障,寫請求寫不過去,所以只有兩個節點包含了值爲 20 的數據。

此時,寫請求會返回給客戶端一個結果,可能會告訴客戶端寫入成功了,也可能告訴客戶端寫入部分紅功。

這時候,當後續的讀請求恰巧被髮送到有通訊故障的那個節點,系統可能只能返回一個空的結果。可是,因爲系統處理和返回了讀寫請求,因此,系統是知足了 CAP 中的可用性的。
在這裏插入圖片描述

疑問二:數據分片和數據副本的分佈式系統是否都遵照 CAP 定理

咱們知道,在一套大規模的分佈式系統裏,必定是既須要把海量數據作切分,存儲到不一樣的機器上,也須要對這些存儲了數據的機器作副本備份的。

那麼,若是,一個分佈式系統裏只有數據分片存儲或者只有數據副本存儲,他們都會遵照 CAP 定理嗎?

答案是當數據分片時,也是要遵照 CAP 定理,可是,是種很是特殊的遵照。

當在一套分佈式系統只有分片存儲的時候,CAP 理論會表現成什麼樣?

好比,咱們有個分佈式系統,由三個節點 a、b、c 組成。其中節點 a 存放了 A 表的數據,b 存放了 B 表的數據,c 存放了 C 表的數據。

若是有一個業務,它的意圖是想往 A 表插入一條新數據,在 B 表刪除一條已有數據,在 C 表更新一條老數據,這個分佈式系統該怎麼處理這種業務?

技術上咱們對這種一個意圖想作多件事的狀況每每會包裝成一個事務。當咱們包裝成一個事務之後,咱們可能會經過先在 a 節點執行,而後去 b 節點執行,最後去 c 節點執行,等到都成功了,纔會返回成功。

可是,發生了分區之後怎麼辦?當在 a、b 節點都成功了,到 c 發現發生了通訊故障?

此時,根據 CAP 定理,你有兩個選擇,要麼就直接返回一個部分紅功的結果給客戶端,要麼直接卡死等客戶端超時或者返回失敗給客戶端。當返回部分紅功的時候,這就是選擇了可用性(A),當卡死或者返回失敗給客戶端的時候,就是選擇了一致性(C)。

但是,咱們將請求包裝成了事務,而事務是要求要麼都成功,要麼都失敗……爲了遵照這種要求,對於分佈式只有分片的狀況,迫於客觀條件,只能選擇C。因此分片的分佈式系統,每每都是 CP 的系統。

可選擇,可是沒法選擇是分佈式系統只有分片數據存儲的狀況時,遵照 CAP 定理的特殊表現。
在這裏插入圖片描述
而當分佈式系統是多個節點,每一個節點存儲了完整的一套數據,別的節點只是完整數據的備份的時候,即便事務只在一臺機器上成功,當發生分區故障的時候,咱們也是能夠有充分的餘地選擇是單機事務的回退 or 就此認爲寫成功的。

單機事務的回退,就能夠對外表現爲選擇了一致性。
在這裏插入圖片描述
就此認爲寫成功,則能夠認爲選擇了可用性。
在這裏插入圖片描述

疑問三:爲什麼有時候區分一個系統是 AP 仍是 CP 是如此之難

由於,就像咱們前面講過的,因爲 AP 或者 CP 的選擇,可能僅侷限爲整套系統的局部,甚至某些特殊的數據上,而咱們又是用這種局部的特性去描述了整套系統,因此就致使了區分的困難。而這自己其實也日漸成爲了 CAP 的一個大問題,從而被人詬病。

6. CAP 的不足

  1. CAP 定理自己是沒有考慮網絡延遲的問題的,它認爲一致性是當即生效的,可是,要保持一致性,是須要時間成本的,這就致使每每分佈式系統多選擇 AP 方式

  2. 因爲時代的演變,CAP 定理在針對全部分佈式系統的時候,出現了一些力不從心的狀況,致使不少時候它本身會把之前很嚴謹的數學定義改爲了比較鬆弛的業務定義,相似於咱們看到,CAP 定理把一致性、可用性、分區容錯都變成了一個範圍屬性,而這和 CAP 定理自己這種數學定理般的稱呼是有衝突的,出現了不符合數學嚴謹定義的問題。

  3. 在實踐中以及後來 CAP 定理的提出者也認可,一致性和可用性並不只僅是二選一的問題,只是一些重要性的區別,當強調一致性的時候,並不表示可用性是徹底不可用的狀態。好比,Zookeeper 只是在 master 出現問題的時候,纔可能出現幾十秒的不可用狀態,而別的時候,都會以各類方式保證系統的可用性。而強調可用性的時候,也每每會採用一些技術手段,去保證數據最終是一致的。CAP 定理並無給出這些狀況的具體描述。

  4. CAP 理論從工程角度來看只是一種狀態的描述,它告訴你們當有錯的時候,分佈式系統可能處在什麼狀態。可是,狀態是可能變化的。狀態間如何轉換,如何修補,如何恢復是沒有提供方向的。

7. 引伸出來的 BASE

正由於 CAP 以上的種種不足,epay 的架構師 Dan Pritchett 根據他自身在大規模分佈式系統的實踐經驗,總結出了 BASE 理論。BASE 理論是對 CAP 理論的延伸,核心思想是即便沒法作到強一致性(Strong Consistency),但應用能夠採用適合的方式達到最終一致性(Eventual Consitency)。

BASE 理論是實踐工程的理論,它彌補了CAP 理論過於抽象的問題,也同時解決了 AP 系統的整體工程實踐思想,是分佈式系統的核心理論之一,咱們將在下一篇文章裏,詳細的講解此套理論。

8. 大廠面試題

在文章最後,來幾道大廠關於 CAP 的面試真題,檢驗一下你的學習效果,hiahiahia

    • 什麼是 CAP 理論?

    • CAP 中的 P 是什麼意思?

    • 爲何說分佈式系統,只能在 C、A 中二選一?

    • 結合實際應用,CP、AP 該怎麼選擇?


 

我準備了一些純手打的高質量PDF:

深刻淺出Java多線程、HTTP超全彙總、Java基礎核心總結、程序員必知的硬核知識大全、簡歷面試談薪的超全乾貨。

別看數量很少,但篇篇都是乾貨,看完的都說很肝。

領取方式:掃碼關注後,在公衆號後臺回覆:666

相關文章
相關標籤/搜索