MongoDB是第一個支援因果一致性的資料庫商業產品

banq發表於2018-10-25

MongoDB版本3.6.4和4.0.0-rc1實現因果一致性(CC)支援,只要使用者一直連線到majority 讀寫會話上,就能實現因果一致性,如果這種CC會話失敗出錯,也能提供不變性約束(資料完整性)。

背景

MongoDBJepsen的長期使用者。在過去的三年中,Jepsen已經為MongoDB進行了多次分析,MongoDB已經將一個龐大的Jepsen測試套件整合到他們的CI系統中。3月,MongoDB要求Jepsen對以前未經測試的配置進行分析:分片群集。我們還開展了關於建模和驗證因果一致性的新研究,這是MongoDB 3.6中的一個新安全功能。

分片叢集sharded cluster
將一個文件看成一個集合,然後切分成元素,這稱為分片,每個分片基於一個欄位稱為shard key,分片鍵。每個分片是獨立分別儲存在MongoDB的不同複製節點伺服器上,一個路由處理器稱為mongos的會將客戶端請求路由轉發到相應的節點伺服器,這些相互複製的節點伺服器集合稱為configsvr,維持叢集中狀態的一致性,包括哪個分片位於哪個節點上的資訊。

由於分片的大小可能會隨著時間的推移而變化,因此MongoDB會將分片進一步劃分為塊chunks。如果分片變得太大,由配置伺服器configsvr驅動的負載平衡器程式將分片拆分成塊,併發布到到其他伺服器產生更均勻的分佈。

因果一致性

因果一致性(CC)是分散式資料庫的一致性模型,它保證始終以相同的順序觀察與因果相關(可以想象成時間先後,這個時間有物理時間和邏輯時間)的操作。例如,只有在問題是可見的情況下才會出現對問題的答覆,這樣問題與答覆就形成了依賴性的因果關係。在此模型中,沒有依賴關係的操作被認為是併發的,併發操作可能沒有明顯的固定前後因果順序。
因果是最終一致和線性化系統之間的眾多中間 選擇之一(banq注:線性化過於注重事務正確性,犧牲效能,比如區塊鏈線性化,區塊是透過前後連這根線串聯起來,最終一致性是過於注重效能而暫時犧牲一些事務正確性,限制了應用場景)。
在最終一致的系統中,只要它們最終收斂,就可以按任何順序觀察操作。線上性化系統中,操作必須以與每個觀察者相同的順序出現,具有硬實時界限。因果一致性允許客戶端僅等待相關操作的子集,而不是等待所有操作的總順序。當總順序太昂貴或無法提供並且允許實現提供改進的可用性時,這尤其有用。
到目前為止,因果一致性一般僅限於研究專案,如COPSBolt-on Causal ConsistencyAntidoteDB ; MongoDB是我們知道的第一個提供實現的商業資料庫之一。
那麼MongoDB如何處理因果一致性呢?如果我們將MongoDB集合標識為一組讀寫暫存器,那麼MongoDB聲稱存在因果一致性的四個保證

  1. 讀取你的寫入:能夠讀取到之前的寫入結果。
  2. 單調Monotonic讀取:讀取操作不會返回比先前一個讀取操作更早的資料狀態結果。
  3. 單調寫入:在其他寫入之前執行的寫入操作必須在其他寫入之前執行。
  4. 寫入跟隨讀取:一個在讀取以後發生的寫操作必須在讀取操作之後執行。

MongoDB客戶端利用會話的概念捕獲因果關係:單執行緒上下文,每個資料庫操作都是在上一個操作之後排序的因果關係都放在這個上下文中。會話與客戶端連線一起存在,並與單個客戶端關聯。每次讀取和寫入時,會話都會傳遞到其呼叫目標節點伺服器,為客戶端提供看到的最高伺服器時間(highest server times)的節點伺服器。
複製副本的節點使用操作日誌(oplog),其中每個操作都由optime標識。Optimes是選舉ID和時間戳的元組,它唯一地標識每個操作。節點只會單調地提前其時間戳以匹配本地掛鐘,或者像Lamport時鐘一樣,來自任何其他節點的最高觀察時間戳。
會話使用時間戳為操作提供單調排序關係。當會話要求伺服器執行操作時,它包括會話觀察到的最後一個時間戳; 伺服器必須等到達到該時間戳才能為請求提供服務。即使在不同的分片之間也是如此:所有副本集中的所有節點基本上共享一個時間戳,而選舉ID僅在各個副本集中有意義。
這提供了單調性,因為一旦操作大部分提交到oplog,則沒有後續操作可以以較低的時間戳進行majority多數提交。同樣地,當以特定時間戳執行多數讀取時,具有相等或更高時間戳的多數讀取器永遠不會觀察到該結果。
會話將其時間戳顯示為因果標記。該令牌可用於強制一個會話觀察另一個會話的結果。也就是說,使用者可以儲存令牌並將令牌傳遞給其他客戶端,甚至是其他節點,以保留因果排序。

問題
我們確實發現了MongoDB的因果一致性問題:除非使用者同時使用majority多數讀寫,否則它不起作用,並且因果一致性文件沒有提到這一點。雖然MongoDB會以更安全的linearizable讀取級別和不安全的寫入問題拒絕因果請求的確認,但它會很樂意接受中間級別,如寫入關注2或本地讀取級別。由於許多使用者出於效能原因使用次要多數sub-majority操作,並且由於因果一致性通常用於高效能本地操作,不需要與其他叢集節點協調,因此使用者可以合理地假設因果會話將確保其sub-majority操作的因果安全性; 但卻不是。
此後,Mongo 向一致性文件新增了大量警告,建議使用者其保證僅適用於majority/ majority操作,這有助於指導使用者正確使用該功能。
即使使用因果會話,即使有majority寫入保證,次要多數sub-majority讀取也可能無法在先前成功寫入時因果關係觀察到,或者未能觀察到先前讀取的值。相反,次要多數寫入可能是可見的,然後在領導者節點伺服器轉換領導權的情況下丟失,這意味著後續讀取可能無法觀察到成功確認的先前寫入。我們將此解釋為違反因果一致性。
MongoDB已經按照設計工作關閉了這個問題,認為對於次要多數寫入和majority讀取,會話實際上確實保持了因果一致性:

即使寫入問題少於多數,也會保留已提交寫入的因果順序。但是,不保證耐用性durable。


MongoDB使用來自掛鐘wall clock的單調時間戳,訊息可能來自其他伺服器的,或來自因果關係啟用的客戶端,使用時間戳作為相關操作之間的排序依據,具有不同選舉ID的兩個領導者可能具有類似的,本地單調的時間戳。因此,基於時間戳的因果會話僅可以對兩個獨立演進的領導者節點執行次要多數sub-majority 操作,同時仍然遵守單調時間戳順序。這就是為什麼我們觀察到次要多數sub-majority操作異常的原因:MongoDB操作的因果結構(通常)不應僅僅透過時間戳捕獲。


 

相關文章