還沒開學,你就被拉去操場軍訓。教官喊:向右看齊。除非你是排頭兵,否則多少要踩出些小碎步,給他點面子。教官只向你發出看齊指令,但如何對齊的命令實際來自你右邊戰友的耳根。

兩週後的你精疲力盡,全班的耳根都被曬黑,但每天第一把向右看齊,總要撲騰好多次。教官照常數落你們:這半個月都練了什麼,爲什麼老是不能馬上排齊?

如果你能掐會打,完全可以懟教官:隊伍本身作爲一個分佈式系統,能馬上排齊那叫奇怪,因爲有 CAP 定理。

一、什麼是 CAP 定理?

分佈式系統中,必然無法同時滿足一致性、可用性和分區容忍性。

分佈式系統指一組電腦連成的網絡。

一致性(Consistency,簡稱 C)指同一時刻全網數據完全一致,相當於軍訓隊伍整齊劃一,越整齊一致性就越高。

可用性(Availability,簡稱 A)一部分節點更新數據後,分佈式系統能基於最新數據響應用戶讀寫請求。排頭兵挪動後,沒跟上的隊伍走樣越小、排齊耗時越少,可用性就越高。

分區容忍性(Partition Tolerance,簡稱 P)只有兩個可選參數:不容忍和容忍。

不容忍分區好比你一個人在 word 裏打字,無需穿行網絡,一臺電腦全盤搞定;容忍分區就是分佈式系統,至少有兩臺計算機聯機組成,比如你保存 word 文檔的瞬間,如果我的電腦沒和你交互,就讀不到你剛寫的文字。

CAP 定理意思是:C、A、P 三者最多得二

具體來說:分佈式系統必然容忍分區(P),所以一致性(C)與可用性(A)註定互斥。如果你想左擁右抱 C 和 A,那就別指望分佈式系統,只能用單機版的中心化方式(不容忍分區,無 P)。

但是,分佈式系統中 C 和 A 的不可兼得,與中文語境下魚和熊掌的不可兼得不同。CAP 定理是說:一條隊伍永遠存在可能不齊的瞬間。這看着像句廢話,但只有理解這點,才能避免對 CAP 原理最習以爲常的誤解:現在不齊,所以永遠無法整齊。

你不是教官腦中的提線木偶,不會根據教官意念自動排齊。排頭兵一個噴嚏把自己打出去半步,二號兵才能開始反應,跟出瞄齊,而他脖子位置的變化向三號兵發出指令:來,跟上。

最後才輪到你,怎麼可能快?所有人的反應時間之外,還要加上挪步用時,於是耗時必然大於零。

映射到分佈式系統:如果想要嚴格一致的數據,那分佈式系統就沒法用了,因爲你無法確保使用數據的瞬間,網絡中其他節點不會更新數據;如果你想用相對新的數據,那就得候着。

所以,分佈式系統天生就慢。

這種慢,更像是遲鈍,原因很簡單:分佈式系統範圍一大,節點間的通信耗時就長。

如果你想獲得可靠的最新信息,就得等所有節點彙集出最新數據,這樣能保住一致性、放棄可用性。可如果你說全網這麼多節點,等到什麼時候才能一致?CAP 原理告訴你:別等了,你就放棄點一致性,先用着吧,否則你啥也用不了。

2000 年加州大學伯克利分校計算機教授布魯爾提出了 CAP 的三選二猜想,兩年後被麻省理工學院的兩位教授基爾伯特和林奇證明。

他們的反證法讓證明過程出奇地簡單:

假設存在一個算法同時滿足一致性、可用性和分區容忍性,那麼在兩個節點的網絡中,存儲的信息分爲不相關的非空集合{G 和 G\’},假設 G 和 G\’ 間沒有通信,那麼,一個節點讀的操作將無法訪問另一節點稍早前寫的結果。

類比一個你熟悉的場景:

媽媽和兒子一起把兩隻蛋關進冰箱,媽媽回房看電視,兒子一餓之下把蛋全煮了扒光吃盡,此時爸爸在房裏問媽媽:冰箱裏還有多少蛋?

媽媽關上房門的剎那,本來共享的雞蛋餘額數據就發生了分區。

如果媽媽追求嚴格一致性,那她應該跑去冰箱檢查餘額後再答覆爸爸,可媽媽追起劇來特別專注,所以直接回答:還有兩個。這個回覆沒有基於準確的最新餘額,但爲了可用,放棄了一致。

可這並不影響爸爸第二天就去超市買蛋,因爲不管零個蛋還是兩個蛋,都不夠全家喫。

所以,一致性並非不可放棄,只是需要權衡。放棄追求一致性,就能少打斷一次電視劇情,少跑一個來回所增加的便利,如果大於因爲蛋數認定不一致帶來的不便,那不一致就不一致吧。

這是很簡單的取捨,但正如“去中心”常被人們誤解爲“去掉所有中心”一樣,人們也常常誤讀 CAP 定理中“三者只能居其二”的含義:

CAP 定理的確告訴我們:分佈式系統中抓走可用性就意味着放手一致性,但並不說明用戶想要的一致性被衝進了馬桶,再也撈不回來。真實情況是,我們可以在短時間內追回些一致性,就像經過嚴格訓練的隊伍可以比普通隊伍用更短的時間排齊一樣。

很可惜,即使我們只用一剎那的時間就能追回先前所有的不一致,我們也沒有辦法追回這一剎那本身所產生的不一致,這是分佈式系統命中註定的無奈。

但這只是 CAP 定理在理論上的陳辭,實際場景中我們需要關注的是如何在 C、A 之間權衡利弊,最終獲得最大的經濟收益。在這方面,銀行業貢獻給我們兩個案例:

二、ATM 機和支票

設計 ATM 時,強一致性是必然選擇,因爲算不清楚錢對銀行來說是件很丟臉的事情。可實際場景中,對可用性的渴求卻超越了一致性,銀行的理由很直白:更高的可用性意味着更高的收入。

ATM 機有三個基本功能:存錢、取錢和查餘額。不管怎麼折騰,只有一條清規必須遵守:用戶借記卡餘額不得小於零。

考慮到存款或查餘額都破不了這條戒律,於是可以放棄一致性、照顧更多可用性:隨時可以存款,儘管存款後的餘額不可能立即傳遍全網;隨時能查餘額,儘管屏幕顯示的餘額未必最新鮮準確。

只有取款操作會被區別對待。

銀行本來可以選擇在發生分區時禁止取款,因爲無法知道準確餘額,但如果執拗於此,會扭傷用戶感情,所以權衡之後只能放手。

銀行可以做兩件事:一是提升內部通信速度,壓縮節點間的通信時長;二是設置限額,比如單次取款最高 5000。

當取款低於限額時,不必拘泥於嚴格的一致性,基於當前餘額讓用戶取到錢是一種體貼,即使這個餘額並非最新最準。於是用戶可以及時取款,銀行也能兜住風險。

你一定看出來了,這是放棄用戶隨時取到借記卡內所有餘額的可用性,轉身捕捉另一種可用性:能隨時取出小額現金,因爲後一種可用性在雙方看來價值都更高。

內部通信徹底完成的瞬間,分區結束,全網信息終於一致,如果此時發現哪位用戶餘額小於零,那銀行就要開始亡羊補牢了。

可用戶通常並非惡意。比如賬戶餘額 6000 元時,用戶父母在老家櫃面用存摺取出 4000,此刻餘額應是 2000,但此餘額信息尚未在分佈式網絡中傳播開,用戶當時在外地 ATM 機上本想取 300,結果多按了一個零,如果 ATM 機依據非最新的餘額,會吐出 3000 塊錢,那銀行就擔着 1000 元的風險。

銀行一般會好意通知用戶,如果不還只能認栽,可因爲概率低損失小,所以沒什麼了不起,而且銀行也會收點費用,就算存取款都免費,每臺 ATM 機還在扮演廣告牌機的角色,7×24 小時地爲銀行高大上的形象加油充電。

總之,ATM 能用就好。

另外一個例子是支票。

作者十年前做櫃員時,支票只能在開戶網點使用,這是銀行單方面選擇一致性的結果,能徹底避免銀行自己喫到空頭支票。

後來爲提升用戶體驗,支票在全市任意網點都能用,唯一的代價是支票沒有一般業務利索,總會遇到卡頓,這是因爲系統想要咬出更多的一致性。

在分佈式場景應用最密集的區塊鏈世界,全網共享一致的最新數據是普通用戶的訴求,但普通用戶和教官一樣,不太可能聽說過 CAP 定理,一時半會無法理解必須折損可用性的事實。

用戶不理解不代表問題不存在,於是各路商業精英紛紛出動,對註定丟失的可用性圍追堵截,集中體現在對共識算法的設計上。

三、各顯其能的共識算法

十年前,作爲一個分佈式應用,比特幣悄無聲息地降生。長大之後,大家被它的慢條斯理震驚了,連小賣部老闆都看不起它,買包牛肉乾這種小事都要等上一個小時。

比特幣的慢是有道理的,道理就是 CAP 定理:爲了在一個分佈式系統內追求全網賬本的嚴苛一致,可用性理所當然地被犧牲,所以只能悶等,直到交易信息被深深刻進鏈上,老闆纔敢把牛肉乾交付客戶。

速度方面,比特幣的用戶體驗低落到極致,但以此爲代價能堅守全網賬本信息一致,最終保證系統安全,那這點慢就忍了吧。

先天的遲鈍性畢竟不是先天性心臟病,但各路英雄爲解決這一缺陷都曾腦漿沸騰,主要落實到兩個方案上:

一是拓寬渠道:把原來雙車道改成八車道,這樣單位時間內能承載更多的信息流,這種方案的結晶分叉出了比特幣現金 BCH。

二是離線交易:礦工忙的時候不會例會壓箱底的那堆小額交易,這是因爲手續費激勵不足導致的動力不夠,那高頻小額交易就由“小銀行”幫你劃轉了吧,你就省錢省心吧,這種方案的結晶就是閃電網絡。

比特幣、BCH 和閃電網絡三者都沒有違背 CAP 原理,後兩者在比特幣原有的嚴格一致性上給予用戶更多可用性,但在更大交易量的衝擊下,可用性和安全性是否會變形,還要讓時間去考驗它們。

保證比特幣一致性的共識算法是 POW,起點思路在於追求完美的一致性,於是只能犧牲很多的可用性。POW 發動全網礦工邊記賬邊猜數,猜到才能獎到,於是猜數字的算力逐漸演化爲系統內的權力。

最終這種格局牢不可破,因爲通過軍訓你也明白了同樣的道理:面對強權只能服從。

後來發展出大家圍坐一起客客氣氣的 POS 共識算法,系統挑出一些區塊生產者,去掉 POW 的猜隨機數環節,產生的區塊交給符合條件的持幣者驗證上鍊。

這大大降低了達成一致所需的時間,可代價卻藏在另外的角落裏。一些 POS 算法會產生一個反直覺的結果:一個塊可以在其後的塊都最終確定後,依然處於未確認的狀態,這樣可能會折損系統層面的安全或穩定。

沒有足夠的時間驗證,所以還沒有定論。

POS 之後,又降生了 DPOS。所有持幣者天然都有等比例的投票權,以此選出一定數量的區塊生產者,不稱職的生產者可被投出局,以此確保全系統的高效安全穩定。

從 Steemit 和 Bitshares 兩個分佈式應用順利運行一到三年的結果來看,DPOS 是當前擴展區塊鏈最出挑的共識算法。但它依然無法跳出 CAP 定理的五指山:再快的 DPOS 也無法在當下瞬間反饋全網其他節點的最新狀態。

重回我們的軍訓場景,教官讓你前後左右地轉,不是讓你曬得更均勻,而是讓你更加習慣服從,讓你不經思考、用神經反射回應他的口令。

你看,多軍訓的確可以讓隊伍更快排齊,但代價是你可能會逐漸失去深入思考的習慣,你會得意於教官嘴裏那條廉價的表揚,但另外那一條條簡單的口令,是我們這代人無處可逃、但要深深警惕的教導。

面對越來越複雜的世界,我們不能不保持深入思考。

結語

作爲科學,CAP 定理宣判了分佈式系統天生的殘缺,但工程學站出來說,我們可以在科學劃出了白線上向外再凸兩步。即使 CAP 定理將一直都在,用把力也許能讓一般用戶感覺不到這根天條的存在。

實際場景中需要思考的是:犧牲的一致性能獲得多大的可用性,於是問題最終變成架在損益天平上的權衡。

權衡就是比大小,日常生活中,我們常常會用一點不那麼要緊的代價,換得非常耀眼的好處。用做數學題的手法去做每個決策,看着很累,可一旦形成習慣就會給人生增色,因爲你的決策系統會發生躍遷。

權衡是基於邊際效用的決策思維,可以讓你擺脫非黑即白的傳統視野,幫你站到高處,理解原本思路的侷促。

區塊鏈的世界裏,常常會看到認知的新邊疆,這讓我們不得不用類比這樣的方法才能高效地溶解新知。我們專欄的風格也一貫如此:站在知識的精準性和可理解性兩端左攀右比,讓你能用最少的耗時溶解新知。

然而,類比本身並非最好,因爲像的意思是不是。不帶成見地觀察、不失理性地校正,纔是最好的學習方式。

——和菜頭

來源鏈接:None