NoSQL 数据库不应该放弃 Consistency
談到 NoSQL,一定會提及一致性(Consistency),按照 CAP 定理,有些 NoSQL 數據庫放棄了一致性,但是 NoSQL 放棄是必然的選擇嗎?
從 1970’s,關系型數據庫(RDB,Relational Database)被發明以來,關系型數據庫就是構建應用的通常的選擇。關系型數據庫對用戶提供 ACID 保證,非常方便開發者使用。從 1990’s 開始,NoSQL 系統開始出現。NoSQL 系統是一類對立于關系數據庫的數據庫系統,他們從架構上放棄了傳統的關系型數據庫的的關系模型和 SQL 的接口。
與 NoSQL 系統相伴而來的 2 個詞是 BASE 和 CAP,這 2 個詞對分布式系統有著非常深遠的影響。我相信就是在這 2 個詞的影響下,很多 NoSQL 系統從架構的初始就放棄了一致性(consistency)選擇了一種最終一致性(Eventual consistency)和可用性 (Availability)。雖然我非常認同 CAP 和 BASE 這 2 個詞,但是我不認為在 CAP 和 BASE 的作用下,NoSQL 系統選擇放棄一致性是一個必然的事情。
首先來回顧一下 CAP 和 BASE 這 2 個概念的歷史。這 2 個概念都是由 Eric Brewer 提出的,Brewer 目前是 Google 公司的基礎設施部門(Infrastructure)的副總裁(VP,Vice President)。在 1997 年,在 SOSP(Symposium on Operating Systems Principles) 上,名為的演講 [1] 總結了 Brewer 等人的近期工作,演講中說他們正在工作的集群服務并沒有采用當時公認的具有 ACID 特性的關系型數據庫作為架構,而是在架構上放棄了關系型數據庫的 ACID 特性。并且為他們的這個架構選擇構造了一個新的詞 BASE,BASE 這個詞的選擇有刻意為之成分,ACID 在英語里有酸性的意思,而 BASE 有堿性的意思,很明顯 BASE 是與?ACID 對立的。
ACID 和 BASE 分別是如下單詞的首字母縮寫:
ACID:Atomicity, Consistency, Isolation, Durability
BASE: Basically Available, Soft State, Eventual Consistency
BASE 主張放棄掉 ACID,主要是放棄 ACID 中的 Consistency,并且讓系統達到基本可用(Basically Available),柔性狀態(Soft State),最終一致(Eventual Consistency)。系統構建者可以不僅僅選擇 ACID,BASE 也稱為一種選擇,也就是在 ACID 和 BASE 中選擇其一。本質上來講,就是在 ACID 代表的一致性 (Consistency) 和 BASE 代表的可用性(Availability)二者之間做出選擇。雖然在 BASE 提出時,還沒有明確說明在一致性和可用性間做出架構選擇,但是已經為后面 CAP 的提出做好了伏筆。
到 2000 年,Brewer 在 PODC(Principles of Distributed Computing)做了名為 [2] 的演講,演講的主旨是闡明如何構建健壯的分布式系統。在這次演講中,Brewer 近一步分析比較了 ACID 和 BASE,并且抽象了 ACID 和 BASE 的核心特性,也就是 ACID 的一致性(Consistency),BASE 的可用性(Availability),并且擴展了第 3 個維度,也就是網絡分區(Network Partition),從而提出了CAP 猜想,這個猜想說:
在分布式系統中,最多能同時滿足以下 3 個屬性中的 2 個:
C (Consistency), A (Availability), P (Tolerance to network Partitions)
根據這個猜想,會存在 3 類系統:
放棄 P,系統具有 CA 特性,這類系統諸如單機數據庫
放棄 A,系統具有 CP 特性,這類系統諸如分布式數據庫、分布式鎖
放棄 C,系統具有 AP 特性,這類系統諸如 web caching、DNS
可用性是非常重要的一個特性,特別是在互聯網行業中,服務宕機對商業的影響是非常大的,所以依據 CAP 定理放棄一致性也就是自然的選擇了。特別是在 Amazon 的 CTO Werner Vogels 詳細介紹了 Eventually Consistent[5] 和 Amazon 的 Dynamo 系統的論文 [12] 發表后,大量追求可用性放棄一致性的 NoSQL 系統出現。
到了 2002 年,GilBert 和 Lynch[3],重新定義了 CAP 這 3 個屬性(重新定義的屬性比 Brewer 猜想中的屬性的范圍小了很多),并且證明了 CAP 這 3 個屬性不能同時達到,從而將 CAP 猜想變成了CAP 定理。
CAP 定理中的 3 個屬性定義如下 [3,6]:
Consistency: 是指原子一致性(Atomic consistency)或者線性一致性(linearizable consistency),這是一種非常高的一致性級別,很少有系統能夠達到。
Availability: 是指完全的可用性,也就是每個到達每個沒有宕機的節點上的讀寫請求都能在一個合理的時間返回一個響應。這里的關鍵點是每個請求到達每個非宕機的節點。這也是一種非常高的可用性水平,也很少有系統能夠達到。
Partition Tolerant: 是指系統能夠在出現網絡分區的情況下,繼續正確響應,即保持系統該有的特性,或者說保持一致性或者可用性。
Glibert 和 Lynch 重新定義的 CAP 定理非常嚴謹,但是只證明了 3 個屬性不能同時具有。然而 Brewer 猜想中的 3 個屬性的定義、3 選 2 的描述,3 分的分類法(AP,CP,CA3 種分類)卻不是非常嚴謹,這也是 CAP 出現之后,很多人懷疑和挑戰 CAP 的原因。Brewer 在 2012 年重新寫了一篇文章 [4],也承認最初的 CAP 表述非常令人誤解。事實上,CAP 定理的適用范圍是非常小的。 雖然 CAP 從出生開始就有很多問題,但是它仍然推動了 NoSQL 運動,很多系統架構者依據 CAP 定理,主動放棄了一致性,但實際上,很多時候這些系統都是不滿足 CAP 定理的適用范圍的。
CAP 的故事到此并未完結,2017 年,Brewer 已經是 Google 公司的基礎設施(Infrastructure)部門的副總裁(VP,Vice President)了,并且這時 Google 公司的第一代 Spanner 系統已經誕生 [9]。Brewer 寫了一篇文章講述了 Google 公司的 Spanner 系統 [7],并且近一步闡述了按照 CAP 定理 Spanner 是一個什么樣特性的系統。在文中,Brewer 指出 Spanner 系統說是 " 實際上的 CA"(effectively CA)系統。從架構上來講,Spanner 是一個 CP 系統,也就是說當出現網絡分區時,Spanner 選擇的是保證數據的一致性,放棄可用性的。但實際上,Spanner 是具有非常高可用性效果的一個系統,從架構上 Spanner 沒有達到 CAP 定理要求的那種完全可用性,但是也達到非常高的可用性,由于采用多副本的設計,個別副本出現網絡分區,并不影響用戶能感知到的可用性。按 CAP 定理的定義,當這些個別副本出現網絡分區時,這些節點是不可用的,也就是系統沒有達到完全可用性。但是此時的用戶請求是可以被其他副本服務的,此時服務是可用的,也就是說用戶仍然感知到 Spanner 是可用的。所以說用戶感知的可用性和 CAP 定理中的可用性不是一個概念。我們追求的應該是用戶感知的可用性。
用戶可感知的可用性,通常用 SLA 來表示,也就是我們通常說的幾個 9 的可用性。Brewer 在文章中也給出了 Google 關于 Spanner 系統的 SLA 的數據,從數據我們可以看到,由于網絡分區導致的服務可用的比例是比較小的,有很大一部分導致服務不可用的原因是諸如軟件 bug、配置錯誤、運維誤操作等導致的。也就是說,即便在架構上采用了達到 CAP 定理要求的可用性,實際用戶可感受到的服務可用性,也就 SLA 也不會提高多少。這也是我從業這么多年的一個體會,系統的不穩定更多來自系統開發者的日常失誤,加強代碼質量,加強開發流程規范,加強生產運維規范,更能大大提高系統的可用性。所以,在架構層面,因為可用性放棄一致性往往是得不償失的。
云計算的大潮下,不放棄一致性也是非常明智的。一個托管在云上的數據存儲服務,如果你放棄了一致性選擇可用性,用戶是感受不明顯,因為使用者不會對架構設計采用達到的 CAP 定理的可用性而買單,用戶只會為你的服務達到 SLA 買單。然而數據存儲服務是否具有一致性,用戶是能夠非常明顯的感受到的。Amazon 公司的內部的 Dynamo[12] 在架構上是可以達到 CAP 定理中的可用性要求的,但是 Amazon 在 AWS 云上售賣的 DynamoDB 并不是采用的這一架構,也許就是出于這個原因 [10]。
那么我們選擇一致性得到的好處是什么那?很多時候,說到一致性時,都會拿金融和錢相關的例子來說明一致性的必要性,但是我相信金融行業并不強依賴一致性 [10]。我認為一致性給我帶來的是開發的方便性。Brewer 雖然提出了 BASE 概念,但是他并沒有詳細闡述這個概念。2008 年 EBay 公司的 Dan Pritchett,寫了一遍文章 [8],通過舉例詳細闡述了在放棄了 ACID 以后,如何采用 BASE 架構實現相同的需求,向我們推薦了 BASE 這種架構模式。通過這篇文章,我們我可以看到如果放棄了 ACID 而選擇 BASE 的話,本來一個非常簡單的功能,需要加入消息隊列等手段才能讓系統達到最終一致性,應用的整體架構復雜了很多。
類似于 Pritchett 文章中說明的一樣,使用不具有一致性的 NoSQL 系統,你需要仔細甄別你的使用場景,判斷你的使用場景是否可以讓你放棄一致性。即便你要使用 BASE 架構,也不是簡單地采用一個具有最終一致性的 NoSQL 系統,替換掉 ACID 數據庫就好了,你需要設計好各種手段,處理掉具有最終一致性的 NoSQL 系統帶來的異常,讓你的整個應用達到柔性狀態和最終一致。BASE 中所說的最終一致和很多 NoSQL 系統所具有的最終一致有些細微的差別。這個差別簡單來說是,BASE 中所說的最終一致是保證系統狀態是正確的;而很多 NoSQL 系統最終一致只保證最終一致,但是不保證這個狀態是你想要的正確的狀態 [11]。
最后,個人的一個觀點是,如果一個 NoSQL 系統做為緩存使用,為了追求低延時,可以放棄一致性,大數據和離線計算的場景類似于這種場景,很多 NoSQL 系統是非常適用的;但是如果 NoSQL 系統作為數據庫來用,那么這個 NoSQL 系統最好不要因為可用性放棄一致性,同時通過多副本技術和良好運維達到實際的高可用性,即達到實際上的 CA(effectively CA),這樣可以大大降低使用者的使用負擔。
由于篇幅所限,本文中關于一致性、CAP、BASE、ACID 的很多技術細節的闡述未能詳盡,擬另行成文討論。成文倉促,有錯漏之處歡迎各位大神指正。
原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的NoSQL 数据库不应该放弃 Consistency的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用NGINX作为HTTPS正向代理服务
- 下一篇: 如何在Flutter上实现高性能的动态模