越说越迷糊的CAP
歡迎跳轉到本文的原文鏈接:https://honeypps.com/architect/cap/
在上一篇《Paxos、Raft不是一致性算法/協議?》中,皮皮簡單地聊了聊一致性(Consistency)與共識(Consensus)的區別。本文再來繼續簡單聊一聊CAP。不管大家有沒有深入了解過分布式系統,相信對CAP應該還是有個比較熟悉的印象。
CAP定理起源于加州大學柏克萊分校(University of California, Berkeley)的計算機科學家埃里克·布魯爾(Eric Brewer)在2000年的分布式計算原理研討會(PODC)上提出的一個猜想。在2002年,麻省理工學院(MIT)的賽斯·吉爾伯特(Seth Gilbert)和南希·林奇(Nancy Lynch)發表了布魯爾猜想的證明,使之成為一個定理。CAP定理也稱為布魯爾定理(Brewer’s theorem)。
對于CAP的具體含義,我們不妨先來看看維基百科對于的解釋。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KgFPEhpz-1584519116520)(http://image.honeypps.com/images/papers/2020/175.png)]
(上圖中維基百科中關于CAP解釋的截圖,這里內容重放一下)在理論計算機科學中,CAP定理(CAP theorem),又被稱作布魯爾定理(Brewer’s theorem),它指出對于一個分布式計算系統來說,不可能同時滿足以下三點:
- 一致性(Consistency) (等同于所有節點訪問同一份最新的數據副本)
- 可用性(Availability)(每次請求都能獲取到非錯的響應——但是不保證獲取的數據為最新數據)
- 分區容錯性(Partition tolerance)(以實際效果而言,分區相當于對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在C和A之間做出選擇。)
針對維基百科的釋義,可用性指的是能獲取到“可以不是最新但要求是非錯的”響應,那么如果我們訪問每一個節點都獲取到了錯誤的響應,那么這在CAP中怎么解釋呢?A不滿足,C中也沒有相關的說明。顯然,維基百科中對于一致性的釋義并不完整。
對于分區容錯性,維基百科中也并沒有直接給出一個精確的定義,而是以“就實際效果而言。。”的襯托手法來釋義,其實是一種含糊其辭的表現。
對于CAP的定義,個人覺得左耳朵耗子在《分布式系統架構經典資料》一文中的解釋比較簡潔明了+到位:
- 一致性(Consistency):每次讀取要么獲得最近寫入的數據,要么獲得一個錯誤。
- 可用性(Availability):每次請求都能獲得一個(非錯誤)響應,但不保證返回的是最新寫入的數據。
- 分區容忍性(Partition tolerance):盡管任意數量的消息被節點間的網絡丟失(或延遲),系統仍繼續運行。
這里以維基百科為例其實是精心挑選的,因為維基百科本身還具有一定的“權威性”,這里我“稍微”批評了一下它對于CAP解釋的不到位(有一說一,維基百科中對于CAP的定義也是整合了的許多權威資料而來的,只能說整理之人未能完全地融會貫通)。很多不太具備“權威性”的文章對于CAP的解釋就更不用說了,比如“三者只可擇其二”,初看上去沒毛病,其實有很多漏洞。
初看去沒錯
在一個分布式系統中,網絡故障和節點宕機是常態,因此網絡分區是一定會出現的。在網絡分區發生時,根據業務需求,系統需要在可用性和一致性之間二選一:
- 優先保證可用性。網絡分區使得有些節點不可達,導致系統不能夠及時同步數據。盡管被請求節點試圖返回其可見范圍內的最新數據,但仍不能保證該數據是全局最新的,即犧牲一致性保證可用性。
- 優先保證一致性。網絡分區使得被請求節點不能夠保證數據全局最新時,返回一個出錯信息給用戶;或者什么也不返回,直到客戶端超時。
實則有漏洞
三者擇其二是要我們將系統分為CA、CP或者AP中的一種,比如傳統的單機數據庫可以看做是CA。其實,系統并不需要在任何時候都必須拋棄 CAP 中的一個。比如系統網絡狀況良好時,并不需要在三者間進行取舍,此時不需要分區容錯,可兼顧一致性和可用性。即:三者可兼顧其三。再換種思路來講。現實中的可用性并不完全與 CAP 可用性 (CAP-availability) 一致。應用程序的可用性可能是通過 SLA 來衡量的 (例如, 99.9% 的合法請求必須在1秒內成功返回響應), 但是這樣的 SLA 指標 CAP 可用 (CAP-available) 和 CAP 不可用 (CAP-unavailable) 的系統都能滿足。現實中的一致性也可類推。很多系統在CAP定理下,既不可用也不一致,嚴格來講,頂多算個“P”。即:三者只得其一。
注:Seth Gilbert和Nancy Lynch對于CAP定理的證明使用的是原子一致性(atomic consistency )和完全的可用性(perfect availability)
說到對于CAP的吐槽,神書《數據密集型應用系統設計》的作者Martin Kleppmann的觀點尤為經典,他曾發文《Please stop calling databases CP or AP》來數落過CAP。在文章的開頭就針對Jeff Hodges的文章《Distributed Systems for Young Bloods 》進行了反駁。
Jeff Hodges在文章中建議用CAP定理來評價一個系統,他認為可以直接將一個系統描述為CP、AP亦或者是CA。Martin Kleppmann對此說道:“我同意 Jeff 的所有其他觀點, 但關于 CAP 定理, 我持有不同意見。CAP 定理過于精簡, 且被廣泛誤解, 導致它對描述一個系統沒有多大用處。所以我懇請大家最好還是放棄 CAP 定理并停止引用和討論。并且我們要用更精確的術語來權衡系統。”
Martin Kleppmann在《Please stop calling databases CP or AP》中還非常霸氣的加了一段話:“Yes, I realize the irony of writing a blog post about the very topic that I am asking people to stop writing about. But at least it gives me a URL that I can give to people when they ask why I don’t like them talking about the CAP theorem. Also, apologies if this is a bit of a rant, but at least it’s a rant with lots of literature references.”,
大致意思是說:“我知道,我寫這篇文章是像在諷刺你們, 不過至少這樣我就有了個url鏈接, 當別人問為什么我不喜歡他們談論 CAP 定理的時候我就可以隨手甩給他們。另外,我很抱歉這篇文章的語氣比較拽, 但起碼我拽的有理有據”。
《Please stop calling databases CP or AP》這篇文章篇幅較長,需要靜下心來細看。比如,Martin Kleppmann認為CAP的定義非常的狹隘:
- 在CAP中,一致性其實指的是線性一致性,這是非常困難的,且不說在分布式環境下,就算是單機多核的情況下,也要通過內存屏障來處理。
- 可用性在 CAP 中定義為 “系統中的非故障節點針對收到的每個請求必須做出非錯誤響應”,這里的問題在于, 某個節點能夠處理請求是不夠的, 任何非故障節點都要能夠處理請求。許多所謂的 “高可用” (即低停機時間) 系統都不符合這種可用性的定義。
- 分區容錯性 (Partition Tolerance)(文章中還多附帶了一句:terribly mis-named,PS:有些英文直譯成中文會失去一些味道) 基本上意味著你的通信建立在可能會延遲或丟包的異步通信網絡上。我們所使用的互聯網和數據中心等都具備這個特性, 所以在這個問題上其實沒有任何選擇.
再比如,CAP 中定理完全沒有提到延遲 (latency), 大家關注的可不僅僅是可用性. 實際上, CAP 可用的系統允許響應無限慢, 并且這樣仍然可以稱作 “可用” 。如果加載一個頁面要2分鐘, 用戶可就不會認為你的系統 "可用"了.
在CAP發表的第12年頭,即2012年, Eric Brewer 也承認 CAP 具有誤導性而且過于簡單化:
自打引入 CAP 理論的十幾年里,設計師和研究者已經以它為理論基礎探索了各式各樣新穎的分布式系統,甚至到了濫用的程度。CAP 理論的表述很好地服務了它的目的,即開闊設計師的思路,在多樣化的取舍方案下設計出多樣化的系統。在過去的十幾年里確實涌現了不計其數的新系統,也隨之在數據一致性和可用性的相對關系上產生了相當多的爭論。“三選二”的公式一直存在著誤導性,它會過分簡單化各性質之間的相互關系。
Eric Brewer 還闡述了他的新觀點:由于分區很少發生,那么在系統不存在分區的情況下沒什么理由犧牲 C 或 A。其次,C 與 A 之間的取舍可以在同一系統內以非常細小的粒度反復發生,而每一次的決策可能因為具體的操作,乃至因為牽涉到特定的數據或用戶而有所不同。最后,這三種性質都可以在程度上衡量,并不是非黑即白的有或無。可用性顯然是在 0% 到 100% 之間連續變化的,一致性分很多級別,連分區也可以細分為不同含義,如系統內的不同部分對于是否存在分區可以有不一樣的認知。要探索這些細微的差別,就要突破傳統的分區處理方式,而這是一項根本性的挑戰。因為分區很少出現,CAP 在大多數時候允許完美的 C 和 A。但當分區存在或可感知其影響的情況下,就要預備一種策略去探知分區并顯式處理其影響。這樣的策略應分為三個步驟:探知分區發生,進入顯式的分區模式以限制某些操作,啟動恢復過程以恢復數據一致性并補償分區期間發生的錯誤。
更多具體內容參考英文原文:http://cs609.cs.ua.edu/CAP12.pdf,中文翻譯版為:《[CAP理論十二年回顧:"規則"變了](https://www.infoq.cn/article/cap-twelve-years-later-how-the-rules-have-changed/ "CAP理論十二年回顧:“規則"變了”)》
為什么寫這些內容?我查閱過很多資料,一是覺得大多數資料說的不清不楚,有明顯的漏洞;二是,隨著分布式理論與實踐的發展,有些東西的含義在慢慢的變化,在迭代升級。越深究越模糊,錯亦對時對亦錯,對亦錯時錯亦對。
其實,對CAP的理解,我們可以簡單地記一下一致性、可用性、分區容錯性這些詞匯,也可以記一下經典的三角關系。不過,CAP的意義在于設計分布式系統時需要考慮取舍,不是一個嚴格的分類方式,并且現代分布式也有更好的模型。CAP 在分布式系統未火熱之時,歸納出了分布式系統設計中所需權衡重要的方向。在云計算、大數據如火如荼的今天,一大批優秀的分布式系統涌現出來,給了我們更多的系統設計的考慮方向和實踐細節。如今做系統設計時,不用太過拘泥于 CAP 原則,根據所面對業務場景,大膽進行取舍即可。
總結一句話:管TM的什么CAP、BASE,安安穩穩CRUD。
除了最后一句,如果其它觀點有錯誤,歡迎在留言區留言探討。 -
歡迎跳轉到本文的原文鏈接:https://honeypps.com/architect/cap/
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
- 上一篇: 聊聊 Java 的几把 JVM 级锁
- 下一篇: So Hot ?快给 CPU 降降温!