聊聊雲原生資料庫的一致性

Zilliz發表於2022-05-20

Raft or not? 為什麼 Consensus-based replication 不是分散式資料庫日誌複製的銀彈?

背景

近期在跟團隊同學聊天的過程中,聽到了這樣一句觀點:

“我們團隊目前的技術路線是不是錯了?基於 Kafka/Pulsar 在做日誌儲存, 感覺更像是在做中介軟體,而不是在做資料庫!”

我在和很多朋友討論的過程中,發現大家對於 Consistency、Consensus、Replication 這些基本概念存在很多誤解,也有很多人認為只有基於 Paxos/Raft 這類分散式一致性演算法的日誌複製才是分散式資料庫的唯一正解。

要說清楚這個問題,首先要梳理清楚下面的幾個基本概念。

Replication

Replication 指的是將資料拷貝到多個位置的過程(不同磁碟、程式、機器、叢集),這一過程通常起到兩個作用

  1. 提升資料的可靠性 - 解決壞盤,物理機故障,叢集異常時的故障恢復問題
  2. 加速查詢 - 多副本可以同時使用來提高效能

Replication 的分類有很多,先明確一點,我們今天討論的是增量日誌的同步方式,而非全量資料的拷貝。

除此之外,常見的 Replication 區分方式還有:同步/非同步,強一致/最終一致,基於主從/去中心化等等。

Replication 模式的選擇會影響系統的可用性和一致性,因此才有人提出了著名的 CAP 理論,在網路隔離無法避免的情況下,系統設計者必須在一致性和可用性之間進行權衡

Consistency

簡單理解一致性,就是同一時間下對於多副本進行讀寫是否可以得到一致的資料。

首先明確這裡我們討論的是 CAP 中的 “C”,而不是 ACID 中的 “C”。對於一致性級別的描述,我認為這篇 CosmosDB 的文件是最為靠譜的 https://docs.microsoft.com/en... (不得不承認 Azure 的產品文件要強過 AWS 不少,且有著滿滿的學院風)

通常 OLTP 資料庫會要求強一致性,或者說線性一致性,即:

  1. 任何一次讀都能讀到某個資料的最近一次寫入。
  2. 任何一個讀取返回新值後,所有後續讀取(在相同或其它客戶端上)也必須返回新值。

線性一致的本質是資料多副本之間新鮮度的保證(recency guarantee),它保證了一旦新的值被寫入或讀取,後續所有的讀都會看到寫入的值,直到它被再次覆蓋。這也就意味著提供線性一致保證的分散式系統,使用者可以不用關心多副本的實現,每個操作都可以實現原子有序。

Consensus

人們希望像使用單機系統一樣使用分散式系統,因此不可避免地引入了“分散式共識”問題。

簡單來說,就是當一個程式提議某一個值是什麼之後,系統中所有的程式對這個值的變化能夠達成一致,下圖就是一個達成一致的過程。

最早的共識演算法來源於 1988 年發表的 Viewstamped Replication 和 1989 年 Leslie 老爺子提出的 Paxos 演算法。

近年來 Raft 演算法也因為其相對而言比較容易實現,而在業界有了大量應用(比如在主流的 NewSQL 中:CockRoachDB、TiDB、Oceanbase 幾乎都是基於 Raft 和 Paxos 實現的)

事實上,共識演算法還有另外一類,也就是 leaderless consensus protocol。

這類演算法被廣泛的運用在區塊鏈中,比如比特幣所採用的 PoW 演算法。這類演算法由於效率問題,較少被應用於併發量較高的資料庫系統中。

值得注意的是,即使採用了分散式共識演算法,也並不意味著系統就能夠支援線性一致性。

當我們在設計一個系統的時候,需要仔細考慮日誌與狀態機器的 commit 順序問題,以及謹慎地維護 Raft/Paxos leader 的 lease,避免在網路隔離的情況下出現腦裂。

Milvus 的可調一致性(Tunable Consistency)實際上非常類似於分散式共識演算法中的 Follower Read 實現。Follower Read 指的在強一致性讀的前提下使用 follower 副本來承載資料讀取的任務,從而提升叢集的吞吐能力並降低 leader 負載。其實現方式是:詢問主節點最新的日誌 commit index ,等待該 commit index 所有的資料順利 apply 到狀態機上,再提供查詢服務。

我們在 Milvus 的設計過程中,並未採取每次查詢都詢問生產者 commit index 的策略,而是通過類似於 Flink 中 watermark 的機制定期通知查詢執行節點 commit index 的位置。這種設計,主要是因為 Milvus 使用者對資料一致性要求並不高,通常情況下可以接受降低資料的可見性換取更高的效能,所以不需要每次查詢都確定 commit index 的位置。

為什麼 Consensus-based replication 會如此流行

簡單來說,就是人們喜歡線性一致性(Linearizability)。

無論是 Raft、ZAB,還是 Aurora 基於 Quorum 的日誌協議,其實在某種程度上都是 Paxos 演算法的變種之一。而線性一致性往往是實現分散式資料庫 ACID 的基礎,這讓這種技術在事務型資料庫中具備了很強的不可替代性。

Consensused-based replication 之所以如此流行,還有以下三個原因:

第一點是相比於傳統主從複製,儘管 Consensus-based replication 在 CAP 理論中更偏重 “CP”,但其依然提供了不錯的 Availability,通常情況下程式崩潰,伺服器重啟都可以在秒級恢復。

第二點是 Raft 的提出極大地簡化了 Consensus 演算法的實現複雜度,越來越多的資料庫選擇了自己寫 Raft 演算法,或者改造目前的 Raft 實現。據不完全統計,Github 上超過 1000 stars 的 Raft 實現就已超過 15 種,最知名的如 Etcd 提供的 Raft 庫以及螞蟻開源的 sofa-jraft,基於這些演算法做二次改造的專案更是不計其數。在國內,隨著 TiKV、Etcd 等開源產品的流行,越來越多的人關注到這一技術領域。

第三點是 Consensus-based replication 從效能上而言,確實能夠滿足現在的業務需求。尤其是高效能 SSD 和萬兆網路卡的推廣,極大地降低了多副本同步的流量和落盤負擔,使得 Paxos/Raft 演算法的使用成為主流。

Consensus-based replication 有什麼問題

諷刺的是,Consensus-based replication 並不是分散式系統解決一切的萬能良藥,恰巧因為可用性、複雜度、效能這些挑戰,導致了它無法成為 replication 的唯一事實標準。

1)可用性

對比弱一致性系統,以及基於 Quorum 實現的分散式系統,Paxos/Raft 在進行優化之後往往對主副本有較強的依賴,導致其對抗 Grey Failure 的能力較弱。Consensus 重新選主的策略往往依賴於主節點長時間不響應,而這種策略並不能特別好地處理主節點慢或者抖的問題:實際生產中太多次遇到因為某些機器風扇壞掉、記憶體故障或者網路卡頻繁丟包導致的系統抖動問題。

2)複雜度

儘管已經有了很多的參考實現,做對 Consensus 演算法並不是一件簡單的事情,隨著 Multi Raft、Parallel raft 之類的演算法出現,日誌和狀態機之間的協同也需要更多的理論思考和測試驗證。相反,我更加欣賞 PacificA、ISR 之類的 replication 協議,藉助一個小的 Raft group 進行選主和 membership 管理,從而能夠大幅降低設計複雜度。

3)效能成本

雲原生時代,EBS 和 S3 等共享儲存方案越來越多地替代了本地儲存,資料可靠性和一致性已經可以得到很好的保證。基於分散式共識來實現資料多副本已經不再是剛性需求,且這種複製方式存在資料冗餘放置的問題(基於 Consensus 本身需要多副本,EBS 自身又是多副本)。

對於跨機房/跨雲的資料備份而言,過於追求一致性的代價除了犧牲可用性,也犧牲了請求延遲(參考:https://en.wikipedia.org/wiki... ),造成效能的大幅下降,因此在絕大多數業務場景下,線性一致性不會成為跨機房容災的剛性需求。

雲原生時代,究竟應該採用什麼樣的日誌複製策略

聊了那麼多 Consensus-based replication 的優勢和劣勢,到底什麼才是雲原生時代資料庫應該採用的 Replication 策略呢?

不可否認,基於 raft 和 paxos 的演算法依然會被很多 OLTP 資料庫所採用,不過我們應該可以從 PacificA 協議、Socrates、Aurora、Rockset 中看出一些新的趨勢。

在介紹具體的實現之前,先提出我總結出的兩個原則:

1)Replication as a service

使用一個專門用於同步資料的微服務,而非將同步模組和儲存模組緊耦合在一個程式裡。

2)“套娃”

前面已經說了,避免 Single Point Failure,似乎逃不開 Paxos 的限制,但如果我們把問題縮小,把 leader election 交給 raft/paxos 實現(比如基於 chubby、zk、etcd 這類服務),那麼 log replication 就可以大幅簡化,效能成本的問題也迎刃而解!分享幾個我很喜歡的設計方案。

第一個例子,我最喜歡的協議是微軟的 PacificA,這篇文章的 paper 釋出於 08 年,相比 paxos 的邏輯完備性,PacificA 更關注工程。當年我們在阿里雲設計自研 Lindorm 資料庫的強一致方案的時候,就發現我們的方案跟 PacificA 非常相似。

微軟的 PacificA 的實現也非常簡單,對於資料同步鏈路,primary 複製給 secondary 的時候等待所有的節點 ack 該請求後,才被認為是提交,因此線性一致性是非常容易保證的。

PacificA 的可用性保證更加簡單,以 Zk、etcd 這一類系統來進行選主、或者完成成員變更操作。也就是說主掛了,lease 消失,備服務會申請替換為主將主節點退群。備掛了,primary 會申請讓 secondary 退群。

第二個例子,我很欣賞的系統是 Socrates,不得不說微軟產品確實很符合我個人的技術審美。

Socrates 的核心特點就是“解耦計算-日誌-儲存”。把日誌和儲存拆開,日誌基於一個單獨的服務來實現。

日誌基於單獨服務實現(XLog Service),利用低延遲儲存實現持久化:在 Socrates 中用了一個元件叫 landing zone,做高速三副本持久化,雖然容量有限,只能做 circular buffer,但是很容易讓我聯想到 EMC 中用帶電容的記憶體做資料持久化。

主節點會非同步將日誌分發給 log broker,並在 log broker 中完成資料落盤 Xstore(較低成本的資料儲存),快取在本地 SSD 進行加速讀取,一旦資料落盤成功,LZ 中的 buffer 就可以被清理。這樣一來,整個日誌資料就分為了 LZ、本地 SSD 快取和 Xstore 三層,近線資料充分利用熱儲存,可以更好地快取提升故障恢復速度和提升 log tailing 的效率。

第三個例子,我認為比較值得一提的是 AWS Aurora,這款資料庫幾乎成為了雲原生資料庫的代名詞。

首先 Aurora 也採用了非常典型的儲存計算分離架構,儲存層是一個針對 MySQL 的定製服務,負責 redo log、page 的持久化,完成 redo log 到 page 的轉換。

Aurora 的強大之處在於使用 6 副本的 NWR 協議保證了寫入的高可用性。相比於 DynamoDB 的 NWR,Aurora 由於只存在 single writer,可以產生遞增的 log sequence numer,解決了傳統 NWR 系統中最難規避的衝突仲裁問題。

事實上,通過 Single DB instance 和儲存層 Quorum 的共同配合,其實是實現了一個類 Paxos 協議。Aurora paper 並未討論上層 DB instance 的故障時如何判斷,不過我的猜測是依然使用了依賴 Paxos、Raft、ZAB 協議的元件切換策略,元件在切換時可能會對下層的 storage 執行 lease recovery,保證不會同時出現雙主發生腦裂(純屬個人猜測,歡迎糾正答疑)。

最後一個例子,有一個有意思的產品叫 Rockset,這是一家由 Facebook RocksDB 原團隊設計的分析型產品。

RocksDB Cloud架構
之後有機會可以單獨聊聊 rockset 這款產品,在我看來它是 Snowflake 之外 OLAP 產品中雲原生做的最好的。這裡不得不提的是,他們像 Milvus 一樣,直接使用了 Kafka/Kineses 作為分散式日誌,使用 S3 作為儲存,使用本地 SSD 作為快取提升查詢效能。更加有意思的是,Kafka 的資料複製協議 ISR 也跟 PacificA 有諸多類似之處,本質上也是一個“套娃”。做雲原生服務,學會通過借力其他服務,降低系統實現複雜度已經是架構師的必修課。

總結

現在,越來越多的雲資料庫,把日誌 replication 做成了單獨的 service。這極大降低了新增只讀副本/異構副本的成本,同時也更有利於日誌儲存服務的效能成本優化。微服務化的設計也可以快速複用一些成熟的雲上基礎設施,這對於傳統緊耦合的資料庫系統來說是不可想象的:這個獨立的日誌服務也許依賴了 Consensus-based replication,也可以採用“套娃”的策略,並且使用各種不同的一致性協議搭配 Paxos/Raft 來實現線性一致性。

最後,再分享一個例子。

很多年前,當我無意間聽到了 Google Colossus 儲存元資訊的方式,不禁為它的設計拍案叫絕:Colossus 基於 GFS 儲存所有的元資訊,GFS 的資料儲存在 Colossus 上,而 Colossus 中最原始的元資訊因為已經足夠小,可以直接儲存在 Chubby 上。這不就是一個“天然的”基於 Paxos 的、類似 Zookeeper 的協調服務嘛。

無論技術如何進步發展,其外在形式如何轉變,深入瞭解和思考“技術發展背後的事情”才是技術人更應該做的事情,也更符合第一性原理思維方式。

參考文獻

  • Lamport L. Paxos made simple[J]. ACM SIGACT News (Distributed Computing Column) 32, 4 (Whole Number 121, December 2001), 2001: 51-58.
  • Ongaro D, Ousterhout J. In search of an understandable consensus algorithm[C]//2014 USENIX Annual Technical Conference (Usenix ATC 14). 2014: 305-319.
  • Oki B M, Liskov B H. Viewstamped replication: A new primary copy method to support highly-available distributed systems[C]//Proceedings of the seventh annual ACM Symposium on Principles of distributed computing. 1988: 8-17.
  • Lin W, Yang M, Zhang L, et al. PacificA: Replication in log-based distributed storage systems[J]. 2008.
  • Verbitski A, Gupta A, Saha D, et al. Amazon aurora: On avoiding distributed consensus for i/os, commits, and membership changes[C]//Proceedings of the 2018 International Conference on Management of Data. 2018: 789-796.
  • Antonopoulos P, Budovski A, Diaconu C, et al. Socrates: The new sql server in the cloud[C]//Proceedings of the 2019 International Conference on Management of Data. 2019: 1743-1756.

作者介紹

欒小凡
Zilliz 合夥人兼技術總監

Linux Foundation AI & Data 基金會技術諮詢委員會成員。畢業於康奈爾大學計算機工程系,曾先後任職於 Oracle 美國總部、新一代軟體定義儲存公司 Hedvig、阿里雲資料庫團隊。曾負責阿里雲開源 HBase,帶領團隊完成自研 NoSQL 資料庫 Lindorm 的研發工作。


Zilliz 以重新定義資料科學為願景,致力於打造一家全球領先的開源技術創新公司,並通過開源和雲原生解決方案為企業解鎖非結構化資料的隱藏價值。
Zilliz 構建了 Milvus 向量資料庫,以加快下一代資料平臺的發展。Milvus 資料庫是 LF AI & Data 基金會的畢業專案,能夠管理大量非結構化資料集,在新藥發現、推薦系統、聊天機器人等方面具有廣泛的應用。

相關文章