用關係型NoSQL回到未來

隨着爲分佈式世界重建遺留RDBMS (ACID事務、關係、約束、規範化建模)的原語,數據庫世界正在經歷復興。

這些新的系統從技術上來說是CP而不是AP,但是有很高的容錯性。

這些系統大多數依賴於Google的Spanner或Percolator協議,使用兩階段鎖,需要物理的同步時鐘來保證一致性。

一些系統採用基於Calvin協議的預提交方法,比如FaunaDB,不需要特別的硬件就能提供更強的保障。

在這兩種情況下,系統開發人員不再需要放棄事務來獲得現實世界中的可伸縮性和可用性。

數據庫復興運動起源於NoSQL,大約是因爲2008年新的一大波互聯網公司(Twitter、Facebook、Google、Amazon)的技術需求遠超傳統的RDBMS能力。另外,像Oracle這樣的RDBMS供應商的價格體系不能夠支持這些新興公司的較小單位經濟效益,尤其是廣告支持的公司。在這種情況下要怎麼做呢?

一開始,公司會使用遺留數據庫作爲存儲引擎的自定義、分佈式數據分片服務,尤其是MySQL和InnoDB。像Memcache和之後的Redis這樣的分佈式緩存無處不在。然而,這些系統不是自運維的,它們仍然需要DBA的干預才能從失敗中恢復。它們不是自動分片的,也不是自修復的。

當時,我在Twitter管理軟件基礎設施團隊,對我們而言,完全有可能構建一個可以透明地大規模和靈活交付的系統,因此,連同業內的其他人,我們開始將其作爲開源項目着手來做,一開始主要是寄希望於Apache Cassandra、Hadoop和其他存儲平臺。當你的業務規模變大的時候,任何會阻礙它前進的東西都需要放棄。

這些數據庫系統的商業供應商號稱他們的系統不能提供某些RDBMS傳統功能,因爲沒人需要這些功能,但這顯然是錯誤的。現在每個企業都需要擴大規模,然而我們爲了使用NoSQL放棄了什麼呢?我們能把放棄的東西拿回來嗎?

最終一致性的實踐效果

CAP理論可以有效地概括爲:當網絡分片時會發生什麼?系統會保證一致性(正確性)而暫時停一下,還是爲了保證可用性,而盡最大努力保證它的運行?其實在實踐中,一致性和可用性的選擇是模棱兩可的,真實世界的情況更加微妙。

第一代NoSQL系統是最終一致的,在分區事件發生之後,它們會在可變但有限的一段時間之內協調衝突,對數據進行概率投票。在現實世界中,很少有這麼複雜的最終一致性系統,相反,它們使用基於本地系統時間的簡單“最後一次寫入獲勝”機制。即使它再智能,對搭建應用程序也沒有實質上的幫助。它需要系統設計人員將整個主機的衝突解決功能引入到應用程序層。

舉個例子

明顯的交易失敗模式如下所示:

  1. Bob在ATM存了200美元。

  2. 數據庫分片接受Bob的“最終一致”存款。他的賬戶餘額200美金更新需要排隊等待。

  3. Bob又通過移動應用程序存了100美元。這次交易更新使用了另一個分片,並複製給其他的集羣,但沒有到原來的分片。

  4. 網絡恢復,複製發生。

  5. 由於第二個交易發生的時間比較晚,所以Bob的餘額根據第3步的分片被更新爲100美元。

Bob現在損失了200美元現金。最終一致性能保證可用性。在這種情況下,我們存錢的數目多少並不能保證正確。

CRDT和區塊鏈

爲了解決這個問題,人們想出了各種方案,特別是CRDT(conflict-free replicated data types),它能幫助有效地關閉所有的中間狀態,保證最終值正確重建。在這種情況下,Bob的交易會被記錄爲借方和貸方,而不只是最終餘額。最終餘額的獲得可以在數據庫或應用程序層中完成。一種例子是區塊鏈,它會記錄集羣上所有節點每時每刻的交易。

然而,在實際操作中,這不能解決所有的問題,因爲數據庫不是封閉的系統。任何數據讀寫的重點在於協調外部影響。如果Bob從ATM取出現金,即使之後CRDT顯示當時他的餘額不足,但是錢也被拿走了。

這並不是一個完全的理論問題。惡意使用ATM的漏洞是一種欺詐行爲。因此,數據庫需要“外部一致性”,就是俗稱的ACID屬性。

遺留解決方案

遺留數據庫(通常是集中的RDBMS)通過非分佈式來解決這個問題。其實說到底,就是一個有單個磁盤的單機,並且出於實際目的,該磁盤基於一個互斥鎖進行更新,事實就是這麼回事。對狀態的更新是序列化的,這代表它們是根據單一、確定的順序發生的,並且是外部一致的,對應着實際發生順序。任何規模化都是出於單機的垂直擴展。

該模型很方便實現,但不能滿足很多關鍵需求,特別是和可用性相關的問題。

因此我們迎來了主從複製系統,主節點可以被DBA手動替換爲從節點,該從節點異步地複製了主節點的狀態。這雖然不是很好,但是不像最終一致性分佈式系統,不一致的範圍是已知的:恰恰是最後一次事務複製到從節點,而主節點發生了外部可見的故障,這之間就出現了不一致情況。

這是互聯網分片系統真實運行的情況:

  • 它們可以在分片(單機)中執行交易。
  • 它們可以手動或半手動地將故障備份到備份分片上。
  • 它們不能同時在多分片進行事務處理。

對於Twitter和Facebook來說這勉強可行,但並不可取。比如說,如果在手機上得到的消息通知在網站上不能讀,這是很奇怪的,但這並不是災難性的。需要事務處理的產品特性(例如,用戶名分配)在遺留的RDBMS中沒有那麼大的伸縮性。

但是隨着產品變得越來越複雜,缺乏外部一致性的劣勢也變得更加嚴重。

Google Spanner

Spanner是Google對於這兩個問題的解決方法。最初它只在Google內部的基礎設施上使用,現在作爲託管產品在Google Cloud上可以獲得。

它完成了兩件事:

  • 多分片事務通過兩階段準備/提交算法實現,基本上類似於20世紀80年代的事務監控協議Tuxedo。
  • 不再依賴HA或是主機級別的硬件來保證可用性,通過Paxos自動實現商品硬件的分片故障轉移。

這個方法在某種程度上很有效果。它保證了可串行化,能根據實時順序對每個單獨的分片進行更新。但它不能保證外部一致性,也不能保證分片之間的實時協調。爲了解決這個問題,Spanner需要做這件事:

  • 物理原子鐘硬件在很小的誤差範圍之內同步所有分片上的系統時間。

現在事務協調器就能放心地說:“分片們,我在T時間做了一個事務,如果你沒有看到在我們共享時間誤差範圍內的其他任何更新,那就是不衝突的”。這引發了每次最終一致讀寫間的小延遲,因爲每個分片都需要等待時鐘模糊窗口。

除去延遲的影響,這對Google來說很可行。它們有資源來構建並管理自定義的原子時鐘硬件和有限延遲的網絡。然而,有許多新的數據庫系統在沒有原子鐘的情況下實現類似的協議,但總是要付出代價的。

基於NTP的Spanner

基於NTP時鐘同步的數據庫有更長的模糊窗口,通常需要幾百毫秒。實踐中,這些系統完全放棄等待,轉而保證沒有外部一致性的單記錄可串行化。這可能會導致類似的交叉線模列和雙借方效果。

它們還不提供快速地外部可串行化讀取,通常從最後一個已知的Paxos leader這裏讀取。這可能違背了可串行化,因爲leader可能不知道它已經被廢棄,於是在選舉窗口(通常是幾秒鐘)愉快地提供了已經廢棄的值。要預防這個窗口的發生需要暫停。

最後,時鐘是否會碰巧不同步,這也是Google花費心思需要預防的,因爲在雲中任何與時鐘無關的事件,比如VM停頓,都會造成這個情況的發生,甚至寫端的可串行化保證都會丟失。

Google Percolator

另一類數據庫查詢單個物理時鐘(Google Percolator的論文中稱其爲”clock oracle”)擁有類似共享時鐘的往返互聯網延遲的模糊窗口,更糟糕的是,還會遇到明顯的單點故障。

這個模型類似於多處理器RDBMS,它也用了單個物理時鐘,因爲它是單機,但是系統總線被網絡所取代。在實踐中,這些系統放棄了多區域擴展,受限於單個數據中心。

很明顯沒有物理時鐘同步,分佈式外部一致性是不可能的,還是有其他方法?

使用Calvin規避物理時鐘

如果你可以創造給所有的事務服務的邏輯clock oracle,不依賴於任何單個物理機器,還可以廣泛分佈,那怎麼樣?這就是Calvin完成的工作。Calvin是耶魯大學Daniel Abadi實驗室開發的。

John Calvin是法國新教改革者,他相信每個人都有最終的宿命,無論是上天堂還是下地獄,都是上帝在創造世界之前決定的。

這也是Calvin的機制。事務的順序是預處理決定的,節點的子集作爲分區的Oracle,給一系列流水線批處理中傳入的事務分配外部一致的順序。之後,批處理用10毫秒的時間提交到分佈式提前寫日誌,可以用Paxos或Raft實現。

這種預處理有很多好處:

  • 它可以在單個網絡往返中完成提交到分佈式日誌,不需要副本上的兩階段鎖。
  • 它的操作拓撲和副本拓撲不同,減少了長尾延遲。
  • 可串行化讀不需要協調,也不需要等待模糊窗口。相反,它們像最終一致性系統那樣在全局內擴展。

然而,它肯定會做出一些讓步:

  • 由於事務是分批提交的,寫延遲不能低於等待下次提交的時間,平均約爲5毫秒,最多可到10毫秒。

FaunaDB進行了一系列性能改進,實現了這個模型,是個關係型NoSQL系統,而不是NewSQL系統,但是沒有什麼特別阻礙FaunaDB最終實現SQL接口的東西。

CAP

儘管沒有CP系統可以在完全任意分區事件中保持活動性,但是在實踐中,我們能發現Spanner和FaunaDB雲系統和AP系統的可用性類似。超過99.9%的可用性故障可能都來自於實現的問題,也可能來自於硬件和網絡的故障,CP系統的一致性模型可以讓它們比AP系統更容易地在故障下驗證。

比如說,五個數據中心的FaunaDB集羣可以承受丟失兩個完整的數據中心,而不影響活動性。同時,類似FaunaDB的CP系統通常可以在較低的一致性級別下維持讀的可用性(比如快照隔離的情況),甚至在分區事件的時候也能實現,這和AP系統一直提供的一致性級別相類似,甚至更好。

理論上來說,將可用性從99.999%提升到99.9999%是不值得的(一年幾分鐘的差別),特別是在暫停期間接受寫的代價是永久的數據不一致。

結論

分佈式事務是計算機科學領域最難解決的問題之一。我們很幸運地生活在這些系統現成的世界裏。任何的有界一致性都比最終一致性要好,甚至拋開其他遺留NoSQL的問題,比如持久性,以及遺留的RDBMS問題,比如運維開銷等等。

然而,除了Calvin之外,其他產品並不能實現沒有物理時鐘的分佈式外部一致性。FaunaDB是唯一實現了類似Calvin事務協議的產品。我推薦你注意你的數據庫系統所提供的一致性保障,並嘗試一下使用FaunaDB。

本文作者

Evan Weaver是Twitter的前任基礎設施總監,他的團隊負責擴展Twitter的後端。他擁有計算機科學碩士學位,之前在CNET和SAP工作過。他是FaunaDB的聯合創始人。

查看英文原文:[Back to the Future with Relational NoSQL](

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章