如何理解資料庫的內部一致性和外部一致性?

如何理解資料庫的內部一致性和外部一致性


感覺現有的答案還沒有答到點上,來談下我的認識。

最初在資料庫文章中見到的"外部一致性",是google提出的,它是為了解釋在分散式事務中遇到的問題而提出的。

這裡的一致性描述的是 非lock base 的事務引擎下,多個事務之間,數據如何相互可見的性質。

多個並發事務讀寫的數據(或數據範圍),它們能夠被資料庫感知到衝突(讀寫之間也算衝突),因此它們在時間線上的順序由資料庫確定,這樣的事務間一致性問題可以被認為是內部一致性問題,ansi sql isolation定義的隔離級別就是定義內部一致性的。

而先後執行(執行區間不重疊)的多個事務,它們的在時間線上的順序由用戶確定,資料庫無法感知到他們之間的關係,它們之間的一致性問題可以被認為是外部一致性問題。

外部一致性問題在lock base或mvcc實現的單機資料庫中並不存在,而在分散式事務中比較常見的不滿足外部一致性的情況是"寫後讀",即提交成功後不能立即能夠被讀到;還有一種更複雜的情況,可以稱之為"半寫後讀",比如客戶端依次執行T1: write A; T2: write B; T3 read A and B,如果沒有全局時鐘,那麼就可能出現T3讀取到最新的B,但是沒能讀取到最新的A。

所以"內部"和"外部"最重要的區別是可見順序由資料庫(內部)確定,還是由用戶(外部)確定。


要把問題說清楚前,先要把「內部一致性」和「外部一致性」這兩個名詞定義清楚。

「內部一致性」搞資料庫的人很少這麼說,一般就直接說一致性,更準確的說是「Consistency in ACID」(「事務 ACID 屬性中的一致性」)。需要跟分散式領域的 Consistency 做一下澄清。自從雲計算蓬勃發展之後,集群環境下的資料庫服務越來越平民化,資料庫和分散式原本兩個有交集但交集不多的領域開始水乳交融,也就出現了名詞打架的現象。打的最厲害的榮耀王者就是「Consistency」(一致性)。事務的 ACID 屬性中有一個 C 是 Consistency,表示事務的執行一定保證資料庫中數據的約束不被破壞。而分散式領域提及的 Consistency 表示系統的正確性模型,著名的也是臭名昭著的 CAP 理論中的 C 就是這個範疇的。CAP 理論的 Consistency 嚴格指 Linearizability[1] 這個一致性模型,與 ACID 中的 Consistency 沒有半毛錢關係,如果你聽到有個搞資料庫的磚家大吹因為 CAP 理論所以分散式資料庫無法保證事務 ACID 的 Consistency,那就別再跟他浪費時間,還不如打王者榮耀更有收穫。題目中的「內部一致性」指的也僅指「Consistency in ACID」。

「外部一致性」的定義是準確的,Gifford 老爺子在他 1981 年的博士畢業論文[2]里 3.1 節,先是定義了 Serializability(可串列化),然後定義了「External Consistency」(外部一致性),指的是符合絕對時間約束的 Serializability。

定義清楚了,也就能看出來「Consistency in ACID」和「External Consistency」是用來描述不同問題的兩個概念,分別是事務 ACID 屬性中的 C(一致性) 和 I(隔離性)。

「Consistency in ACID」是事務提供的非常強有力的功能,它的核心是「約束」,而這個「約束」由資料庫的使用者告訴資料庫,使用者要求數據一定是符合這樣或者那樣的約束條件。當數據發生修改時,資料庫會檢查數據是否還符合約束條件,如果約束條件不再被滿足,那麼修改操作不會發生。關係資料庫最常見的兩類約束是「唯一性約束」和「完整性約束」,表格中定義的主鍵和唯一鍵都保證了指定的數據項絕不會出現重複,表格之間定義的參照完整性也保證了同一個屬性在不同表格中的一致性。「Consistency in ACID」是如此的好用,以至於已經融化在大部分使用者的血液里了,使用者會在表格設計的時候自覺的加上需要的約束條件,資料庫也會嚴格的執行這個約束條件。這就好像國家的計劃生育政策,祖國規定了每個家庭最多只能生育兩個孩子,那每個人都需要遵守。能不能生是能力問題,遵不遵守是...呃,就是必須遵守。

「External Consistency」的核心是「並發控制」。當資料庫系統從批量處理進化到在線實時系統後,事務就可以並發地在資料庫上進行操作,在給使用者帶來便利的同時也給資料庫系統開發人員帶來了諸多困難。嚴肅的資料庫系統都會有一套複雜的並發控制機制來保證事務並行執行時數據的正確性。事務 Isolation(隔離性)最大的煩惱來自並發控制對性能的影響,最嚴格的隔離性 Serializability 保證了所有的事務雖然是並發執行,但是最終執行的結果跟事務一個個串列著做是一樣的,可串列化保證了一定不會因為並發進行的事務導致數據出錯,但是這也會導致事務有更多等待或者失敗。其他常見的隔離級別還有 Repeatable Read、 Read Committed 和 Snapshot Isolation,他們都比 Serializability 要弱,並不能保證事務一個個順著做,換句話說,事務執行過程中能感受到它自己不是一個人在戰(執)斗(行)。常見的隔離級別裡面沒有 External Consistency,因為一般不怎麼需要這個級別,尤其是在單機資料庫系統里。實際上 External Consistency 比 Serializability 更嚴格。Serializability 已經保證了事務是一個個串列做的了,怎麼還有更嚴格的保證呢?還真有,External Consistency 除了在串列做之上,還對事務串列的排列順序提出了更多的要求。要求是這樣的,如果一個事務 A 已經完成了,另一個事務 B 才開始,那麼事務 B 在資料庫里修改的數據的生效時間一定要在事務 A 的生效時間之後。這是一句廢話嗎?對於常見的單機資料庫,這確實是廢話,因為保證 A、B 的先後關係不費吹灰之力,所以一般單機資料庫系統都隱含保證了這一點。但是在分散式資料庫里,當 A、B 兩個事務發生在不同的機器上時,保證先後關係是非常困難的,所以才用 External Consistency 專門描述這種特性得到了保證。實際上,Helihy 也曾經在 Linearizability 的論文[1]里討論了 Strict Serializability,也是在 Serializability 的基礎上加上了絕對時間的約束。所以,External Consistency 和 Strict Serializability 是完全等價的。至於為什麼在分散式系統中保證 External Consistency 很難,值得在另一個話題中討論。有一點讓很多人疑惑的是,為什麼 Serializability 最初沒有加入絕對時間的約束,而是允許一些看似不合理的現象發生,例如,先成功寫入一條數據,再用一個只讀事務讀這個數據,結果返回不存在,這樣的行為並不違反 Serializability,神不神奇。只是現在主流的資料庫都不會做得這麼二,所以大多數人也無從感知。可是,從嚴謹的學術定義上,Serializability 就是這麼二,現在的科研人員也已經不清楚當初的資料庫眾神是怎麼想的了[3]。

終於,完成了這兩個概念的解釋,列一些文章給你參考:

[1] Linearizability: A Correctness Condition for Concurrent Objects

[2] Information Storage in a Decentralized Computer System

[3] Linearizability versus Serializability


看完了參考文章才到了重點,對,我要播廣告了。OceanBase 是螞蟻金服內部孵化的業界領先的分散式關係資料庫,我們一直走在分散式資料庫研發的最前沿,上面這種探討就是我們的日常。我們一邊在生產系統中解決雙 11 這種史詩級的系統負載,一邊在軟體升級迭代中探索分散式資料庫的美好未來。在分散式與資料庫的碰撞中,在新的硬體環境和現實問題的激勵中,資料庫正在進行新一輪的發展。如果你現在在其他領域但是對資料庫非常感興趣,或者你已經是資料庫領域的專家希望有一個地方一展身手,都歡迎給我私信,我們一直在招人。


謝邀,強答。

1.張文亮老師貼出了Google的解釋「The external consistency constraint requires that the data used by a transaction reflect the physical environment at the time; this is in contrast to internal consistency which requires that all data must meet some predefined constraints in the database。」。這個解釋可以稱得上是深入淺出了。

2.基於這個描述,我用spanner作為例子在展開說說。

spanner中的內部一致性:數據寫入spanner後,每份每行數據都存在多個副本中,每行數據都可能會被任意順序和頻次的增刪改,那麼假如上帝存在,上帝去看(當然不是通過客戶端連接上去看)單獨每行數據的時候,去檢查數據的多個副本是否一致,這個就是屬於內部一致性。這個內部一致性,就是靠PAXOS協議保證的。

spanner中的外部一致性和傳統資料庫很多重合,RR,SR,SSR等;除此之外,還有個很有意思的一致性問題,read-after-write,即數據寫入後必須立刻能讀到。這個顯而易見的道理在分散式資料庫中卻比較難解決的,其關鍵原因就是在於分散式資料庫中,每個server獨立維護數據版本,沒有統一的時間戳生成器(或者說版本號)。在spanner中,解決方案就是true time,簡單來說,就是搞了一個可比的、近似的全局時鐘,具體實現,可以去看看論文。


ACID的C和CAP的C是不一樣的。

資料庫教科書里提煉的,ACID的C指的是從業務層面定義約束,例如銀行轉賬場景,轉入和轉出金額要平衡,又或者外鍵指向的行必須存在,這個C一方面依賴資料庫的保證,例如原子性,也依賴於業務特性和業務層代碼實現。

CAP的C是現代分散式系統中大家經常談到的一致性,其內涵和外延比較豐富。例如,ACID中的I,在分散式系統中如何保證並發Query的隔離級別Isolation,可以認為是一種一致性;多副本間達到一致狀態機如Paxos和Raft,也是一種一致性。


對外部一致性的認知,主要來自於Spanner的Paper。寫下自己讀Paper過程中的理解吧。

個人認為,外部一致性描述的不是並發問題,而是在物理時間上先後發生的事務間的關係

外部一致性的目標是:假設事務T1執行完成後,T2才啟動,保證讓T2看到T1的結果。

這個目標看起來比較好實現,因為T2開始時,T1已經執行完成了。那為什麼外部一致性成為Spanner的主要問題?主要來自兩個方面:

1) T1和T2的時間戳可能來自位於不同Region的Server(Server一般是某個paxos group的 leader);

2) 不同region間的server之間,時間沒法嚴格同步,即存在誤差。(雖然Spanner用了高大上的硬體以及配套演算法來同步時鐘,仍然不能絕對保證跨region的伺服器的時鐘嚴格同步。因為跨了延遲達到100ms的廣域網。)

舉個例子來討論吧: 用戶A給帳戶X存款10萬(對應事務T1),發生在中國;用戶B查詢帳戶X的餘額,對應事務T2,發生在美國。

我們把伺服器的誤差稍微放大點,比如10s。

1) 存款事務T1執行時,獲取的提交時間戳為t;

2) T1執行完成後,A打電話給B,說錢已經存上了;

3) B去查詢(事務T2),T2獲取的時間戳可能是 t - 5s; 由於t-5s &< t,按照時間戳比較,根本查詢不到T1的結果(按照物理時間,T1在T2啟動前已經完成,二者並非並發,執行結果違背了外部一致性)。


強貼一發。

1. 內部一致性

ACID的C比較簡單,比如多個事務並發執行轉賬業務:A轉給B一塊錢,無論成功與否(A+B)的總額是不變的。

2. 外部一致性

對於分散式資料庫執行上面的轉賬操作:

A在分區1,執行A-1 --phase1

B在分區2,執行B+1 --phase2

假設phase1操作成功,phase2失敗,這時候總額是少了1塊的,這就破壞了分區間數據一致性,所以需要分散式事務來保證。

還有一種情況是多個事務並發的執行上面的操作,最終的結果是否符合(A+B)的總額不變。

比如Spanner的truetime來保證linearizability,向Strict consistancy前進了一步,具體請參考:

Cloud Spanner: TrueTime and External Consistency

https://cloud.google.com/spanner/docs/true-time-external-consistency

注: Spanner的文檔很值得看,技術科普文


相對於 ACID 而言,這兩個概念似乎不那麼常見。Google 出來的第一個結果:

The external consistency constraint requires that the data used by a transaction reflect the physical environment at the time; this is in contrast to internal consistency which requires that all data must meet some predefined constraints in the database.

Consistency issues in real-time database systems - IEEE Xplore

http://ieeexplore.ieee.org/iel2/233/1806/00048069.pdf

不確定是不是提問者所需要的。


我也來簡單答一下吧,知乎首答。

基於提交時間戳來進行可見性判斷的mvcc機制(oracle,spanner,cockroach都是這樣的),重要的兩個時間戳是事務提交時間戳和讀操作snapshot時間戳。

外部一致性是spanner引入的。我理解spanner的相關機制主要解決分散式環境下的以下兩個問題:

1.寫後寫,在客戶端看來,如果寫事務txn1先提交,寫事務txn2後開始(比如同一session內先後執行的事務),那麼txn1的提交時間戳必須小於txn2的提交時間戳。

2.寫後讀,在客戶端看來,如果寫事務txn1先提交,讀操作txn2後開始,那麼txn1的提交時間戳必須小於txn2的snapshot時間戳。

否則的話自己腦補吧 。。


強答。只是個人理解,僅為討論,別當作知識。

我第一次看到外部一致性這個詞,也是在spanner的論文中(paper看的少)。我始終覺得搞出這麼個「外部一致性」的概念,完全是人為的把問題複雜化了。我認為問題的複雜性分兩類,一類是因為事務本身的客觀規律導致的複雜性,另一類是人為搞出的複雜性,比如兼容歷史遺留系統或者提出一個古怪的概念。我認為這個「外部一致性「就是人為搞出來的複雜性,反而容易迷惑人。因為我覺得用現有的理論和概率就能解釋它所說的「外部一致性」

一致性這個詞用的地方太多但是含義有比較模糊,以至於我們每次說到一致性的時候,它的具體含義必須依賴上下文。

我來試圖理解為什麼有人要分出個「內部一致性」和「外部一致性」(其實我並不理解)。外部一致性主要是分散式系統引入的一個問題,在分散式系統中用戶如何能像傳統單機資料庫一樣看到一個一致的視圖,除了AID以外,多了一個全局時鐘的問題。比如CockroachDB採用的全局邏輯時鐘,用戶以物理時鐘(wall clock)來看的話,發現會有不一致的問題(相比傳統傳統單機DB)。至於「內部一致性」,完全是為了區別「外部一致性」而搞出的一個概念,本身並沒有更多的含義,我簡單理解為傳統的ACID和分散式系統中的副本一致性。

簡單表述就是:內部一致性是指事務的順序是由每個事物獲取快照(或者事務id)的先後順序來決定的。外部一致性是指事務的順序是有客戶端發起請求的順序來決定的。

最經典的ACID,初學的時候,AID都不難理解,但是C特別難以理解。

我現在對ACID的理解是:這個C根本就不應該跟AID並列在一起,他們不是一個層面的東西。我贊同前面大神的答案,C本質上就是用戶對資料庫的要求。

教材中講到ACID的C大都類似這樣來描述的:一致性就是滿足資料庫的約束;然後會舉一個經典的轉賬的例子(這個就不用重複了吧)。我個人覺得用這個例子來解釋ACID的C,完全就是和稀泥,目的就是讓你蒙逼。這個轉賬例子說的明明是A(原子性)和D(持久性),並不能解釋C。

我是這麼理解ACID的C的。

C = AID + 約束

這個約束包含兩層含義:一個是業務在資料庫上定義的,資料庫能感知的約束;另一個是資料庫不能感知但是業務要求的約束。

第一類資料庫能感知的約束:比如餘額必須大於0(欄位約束),或者一個人的死亡時間必須晚於出生時間(表約束),或者每個人只能出現一次(唯一性約束)等等。甚至,寬泛一點講,隔離級別,用戶告訴資料庫說為了最求高並發,某些場景下出現的某些數據不一致(用可串列化的要求來看到的不一致)我也可以接受。

第二類資料庫不能感知到的約束:比如轉賬的例子,兩個人的餘額之和必須不變。用戶層面的約束是通過資料庫的原子性來保證的。資料庫並不能感知到這個業務邏輯,它只能感知到用戶告訴他的這兩個操作必須在一個事務裡面。甚至,用戶也可以自定義一些完全有業務層來保證的一致性約束。

總之,對於資料庫系統來說,ACID中的C到底一個「需求」,這個需求可以分解為AID和約束。(是不是這個C定義成Constraint)

再說分散式系統,用ACID也是可以來解釋它的一致性的,只是ACID中沒有像AID一樣把網路和全局時鐘的問題考慮進來。網路和全局時鐘對分散式資料庫一致性的影響就是兩類(我的理解):事務一致性和副本一致性

事務一致性就是如何保證分散式系統中的A(原子性)和I(隔離性,因為時鐘不一致),通常用的手段就是2PC或者3PC啥的。

副本一致性就是如何保證跨物理空間對同一份邏輯數據的多個副本的一致。通常就是raft/paxos等。當時也不絕對,用2PC也能解決副本一致性,當我們通常不會這麼干。

在把一致性發散一點,整個IT系統的一致性,比如緩存和持久化的一致性,cpu cache和內存的一致性等等。總是,一致性這個問題,越搞越糊塗。


外部一致性是融合了資料庫事務的隔離級別對應的一致性(串列化,快照,讀提交,臟讀等),還有分散式系統的多副本一致性(線性化,pram,mav,有界,前綴,最終,弱等),為什麼這樣設計?因為應用是廣域接入,資料庫是廣域分布,因此需要把資料庫系統作為黑盒,黑盒對外部客戶端是一致性的,這就要兩個概念合在一起。

問題的關鍵就轉換成怎麼即保證並發的隔離性,又要保證副本一致性。tt就來了。

隨便說說,講的不能太深入了,畢竟涉及很多領域的知識。


內部一致性是應用級別的要求,比如銀行系統轉賬從A轉到B A+B應該保持不變。內部一致性是依靠AID來實現的。ACID中只有C是應用級別的要求,AID都是系統級別的要求。

外部一致性CAP中的C指的是,分散式系統中對於各個replica的操作能否滿足linearizability. 如果可以滿足,我們則認為其滿足strong consistency即CAP中間的C。如果不滿足linearizability,則是eventual consistency。

兩者之間幾乎沒有什麼聯繫,除了都用了一致性也就是consistency這個詞。


推薦閱讀:

剛開始學習資料庫對資料庫概念一竅不通。?
如何系統學習 MySQL?
個人網站,資料庫如何設計存儲富文本文章比較好?
想真正從基礎到深入地學習資料庫,但是市面上的數據過多,有什麼好的書籍,網站嗎?
Android 開發中為什麼很少使用 JSON 存儲數據?

TAG:資料庫 | 分散式系統 | 分散式資料庫 |