做者:Eric Fu\
連接:https://ericfu.me/yugabyte-db...java
Yugabyte DB 是一個全球部署的分佈式數據庫,和國內的 TiDB 和國外的 CockroachDB 相似,也是受到 Spanner 論文啓發,因此在不少地方這幾個數據庫存在很多類似之處。git
與 Cockroach 相似,Yugabyte 也主打全球分佈式的事務數據庫——不只能把節點部署到全球各地,還能完整支持 ACID 事務,這是他最大的賣點。除此之外還有一些獨特的特性,好比支持文檔數據庫接口。若是我猜的沒錯,Yugabyte 早期被設計成一個文檔數據庫,後來才調整技術路線開始主打 SQL 接口。github
本文信息主要來自於 Yugabyte 的官方文檔:面試
https://docs.yugabyte.com/
以及其 GitHub 主頁:spring
https://github.com/yugabyte/y...
邏輯上,Yugabyte 採用兩層架構:查詢層和存儲層。不過這個架構僅僅是邏輯上的,部署結構中,這兩層都位於 TServer 進程中。這一點和 TiDB 不一樣。數據庫
Yugabyte 的查詢層支持同時 SQL 和 CQL 兩種 API,其中 CQL 是兼容 Cassandra 的一種方言語法,對應於文檔數據庫的存儲模型;而 SQL API 是直接基於 PostgresQL 魔改的,能比較好地兼容 PG 語法,據官方說這樣能夠更方便地跟隨 PG 新特性,有沒有官方說的這麼美好咱們就不得而知了。網絡
Yugabyte 的存儲層纔是重頭戲。其中 TServer 負責存儲 tablet,每一個 tablet 對應一個 Raft Group,分佈在三個不一樣的節點上,以此保證高可用性。Master 負責元數據管理,除了 tablet 的位置信息,還包括表結構等信息。Master 自己也依靠 Raft 實現高可用。架構
這一部分是 HBase/Spanner 精髓部分,Cockroach/TiDB 的作法幾乎也是如出一轍的。以下圖所示,每張表被分紅不少個 tablet,tablet 是數據分佈的最小單元,經過在節點間搬運 tablet 以及 tablet 的分裂與合併,就能夠實現幾乎無上限的 scale out。每一個 tablet 有多個副本,造成一個 Raft Group,經過 Raft 協議保證數據的高可用和持久性,Group Leader 負責處理全部的寫入負載,其餘 Follower 做爲備份。intellij-idea
下圖是一個例子:一張表被分紅 16 個 tablet,tablet 的副本和 Raft Group leader 均勻分佈在各個節點上,分別保證了數據的均衡和負載的均衡。app
和其餘產品同樣,Master 節點會負責協調 tablet 的搬運、分裂等操做,保證集羣的負載均衡。這些操做是直接基於 Raft Group 實現的。這裏就再也不展開了。
有趣的是,Yugabyte 採用哈希和範圍結合的分區方式:能夠只有哈希分區、也能夠只有範圍分區、也能夠先按哈希再按範圍分區。之因此這麼設計,猜想也是由於 Cassandra 的影響。相比之下,TiDB 和 Cockroach 都只支持範圍分區。
哈希分區的方式是將 key 哈希映射到 2 字節的空間中(即 0x0000
到 0xFFFF
),這個空間又被劃分紅多個範圍,好比下圖的例子中被劃分爲 16 個範圍,每一個範圍的 key 落在一個 tablet 中。理論上說最多可能有 64K 個 tablet,這對實際使用足夠了。
哈希分區的好處是插入數據(尤爲是從尾部 append 數據)時不會出現熱點;壞處是對於小範圍的範圍掃描(例如 pk BETWEEN 1 AND 10
)性能會比較吃虧。
每一個 TServer 節點上的本地存儲稱爲 DocDB。和 TiDB/Cockroach 同樣,Yugabyte 也用 RocksDB 來作本地存儲。這一層須要將關係型 tuple 以及文檔編碼爲 key-value 保存到 RocksDB 中,下圖是對文檔數據的編碼方式,其中有很多是爲了兼容 Cassandra 設計的,咱們忽略這些,主要關注如下幾個部分:
key 中包含
value 中包含
若是撇開文檔模型,key-value 的設計很像 Cockroach:每一個 cell (一行中的一列數據)對應一個 key-value。而 TiDB 是每一個 tuple 打包成一個 key-value。我的比較偏好 TiDB 的作法。
和 TiDB/Cockroach 同樣,Yugabyte 也採用了 MVCC 結合 2PC 的事務實現。
時間戳是分佈式事務的關鍵選型之一。Yugabyte 和 Cockroach 同樣選擇的是 Hybrid Logical Clock (HLC)。
HLC 將時間戳分紅物理(高位)和邏輯(低位)兩部分,物理部分對應 UNIX 時間戳,邏輯部分對應 Lamport 時鐘。在同一毫秒之內,物理時鐘不變,而邏輯時鐘就和 Lamport 時鐘同樣處理——每當發生信息交換(RPC)就須要更新時間戳,從而確保操做與操做之間可以造成一個偏序關係;當下一個毫秒到來時,邏輯時鐘部分歸零。
不難看出,HLC 的正確性實際上是由 Logical Clock 來保證的:它相比 Logical Clock 只是在每一個毫秒引入了一個額外的增量,顯然這不會破壞 Logical Clock 的正確性。可是,物理部分的存在將本來無心義的時間戳賦予了物理意義,提升了實用性。
我的認爲,HLC 是除了 TrueTime 之外最好的時間戳實現了,惟一的缺點是不能提供真正意義上的外部一致性,僅僅能保證相關事務之間的「外部一致性」。另外一種方案是引入中心授時節點(TSO),也就是 TiDB 使用的方案。TSO 方案要求全部事務必須從 TSO 獲取時間戳,實現相對簡單,但引入了更多的網絡 RPC,並且 TSO 過於關鍵——短期的不可用也是極爲危險的。
HLC 的實現中有一些很 tricky 的地方,好比文檔中提到的 Safe timestamp assignment for a read request。對於同一事務中的屢次 read,問題還要更復雜,有興趣的讀者能夠看 Cockroach 團隊的這篇博客 Living Without Atomic Clocks:
https://www.cockroachlabs.com...
絕不驚奇,Yugabyte 的分佈式事務一樣是基於 2PC 的。他的作法接近 Cockroach。事務提交過程當中,他會在 DocDB 存儲裏面寫入一些臨時的記錄(provisional records),包括如下三種類型:
事務的狀態信息保存在另外一個 tablet 上,包括三種可能的狀態:Pending、Committed 或 Aborted。事務從 Pending 狀態開始,終結於 Committed 或 Aborted。
事務狀態就是 Commit Point 的那個「開關」,當事務狀態切換到 Commited 的一瞬間,就意味着事務的成功提交。這是保證整個事務原子性的關鍵。
完整的提交流程以下圖所示:
另外,Yugabyte 文檔中提到它除了 Snapshot Isolation 還支持 Serializable 隔離級別,可是彷佛沒有看到他是如何規避 Write Skew 問題的。從 Release Notes 看來這應該是 2.0 GA 中新增長的功能,等更多信息放出後再研究吧!
如下表格摘自 Compare YugabyteDB to other databases:
https://docs.yugabyte.com/lat...
近期熱文推薦:
1.600+ 道 Java面試題及答案整理(2021最新版)
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.阿里 Mock 工具正式開源,幹掉市面上全部 Mock 工具!
4.Spring Cloud 2020.0.0 正式發佈,全新顛覆性版本!
以爲不錯,別忘了隨手點贊+轉發哦!