06.05 如何打造一款 NewSQL + MySQL 的分佈式數據庫?

對分佈式數據庫感興趣的朋友都知道,谷歌的 F1 和 Spanner 引領了 NewSQL 技術的發展,於是很多公司去做 NewSQL,導致好多人認為基於 MySQL 的分佈式數據庫過時了。

其實不然,MySQL 並沒有過時,本篇文章的主角 —— RadonDB ,就是把 NewSQL 領域比較流行的分佈式一致性算法和 MySQL 結合起來,形成了新一代的分佈式數據庫 MyNewSQL,同樣做到了可擴展、高可用、強一致、易部署的特點。

那麼,如何將 NewSQL 領域比較流行的技術和 MySQL 結合起來,打造一款新的分佈式數據庫?

1

RadonDB 的架構

如何打造一款 NewSQL + MySQL 的分布式数据库?

首先看一下 RadonDB 的架構,如上圖所示,上半部分是分佈式的 SQL 層,下面是存儲層,如果我們對 F1 和 Spanner 進行抽象之後,會發現也都是這兩層。

其中 SQL 層主要負責對用戶 SQL 解析,然後生成分佈式的執行計劃和執行器,再把這些執行器下發到具體的存儲節點去執行。

雖然架構看上去比較一致,但 RadonDB 比較特殊的一點是:下面的存儲層有多個存儲節點。圖中每個圓圈裡面都是一個存儲節點,每個存儲節點有三副本,三副本之間就是一個 Raft 協議進行數據同步,每個副本都是一個 MySQL。而其他 NewSQL 就是一個 KV 或者其他的存儲。

2

RadonDB 架構層解析

下面詳細闡述一下架構裡面的各個技術點。

SQL 節點

如何打造一款 NewSQL + MySQL 的分布式数据库?

首先來看一下 SQL 節點。

用戶請求到達 SQL 節點後,我們根據數據的分佈規則生成一個分佈式的執行計劃,告訴用戶的 SQL 要分發到哪些存儲節點,然後根據分佈式執行計劃生成一個分佈式的執行器,就是具體到哪些存儲節點進行鏈接、執行、返回。

執行完之後 SQL 節點就會做二次運算,為什麼叫二次運算?因為下面是 MySQL,SQL 節點把計算推到 MySQL 之後,SQL 節點再進行二次運算,包括 limit/groupby/aggregation/join。

所以說,SQL 節點是一個無中心化、無狀態的,擴容性強。

3

存儲層

如何打造一款 NewSQL + MySQL 的分布式数据库?

存儲層由多個 Node 組成,每個 Node 就是一主兩從的 MySQL,但這個 MySQL 比較特殊,因為 MySQL 沒有一個高可用的方案,可能大家都是 MHA 或者自己寫一個主從切換腳本來運維。

但是 RadonDB 引入了 Raft 協議,它是無中心化的, 當主庫掛了後,通過 Raft 協議選擇新主,而數據同步則基於 MySQL GTID 機制。

基於 MySQL 的好處是不僅有存儲能力還有計算能力,如果一個副本只是一個 KV ,他的計算能力就比較有限,SQL 層把數據推到存儲層,然後再返回 SQL 節點再進行運算,這樣存儲層和 SQL 層交互就會比較多。

我們儘量把計算能力下推到存儲層讓 MySQL 完成,因為 MySQL 跟數據是在一塊的,不涉及網絡傳輸,只需要幾個 I/O 就將數據過濾掉了。

4

數據分佈

如何打造一款 NewSQL + MySQL 的分布式数据库?

剛才說了 SQL 層和存儲層,再看一下數據怎麼分佈?

建一個 T1 表,後面指定的分區方式是 HASH,在 RadonDB 裡面默認整張表共 4096 slots, 每個小表默認是 128 slots, 其實就是一個大表分成 32 個小表,比如兩個存儲節點,這個 T1 表的 32 個小表,前 16 個小表在第一個存儲節點上,後 16 個小表是在第二個節點上,是均分佈的。

可能很多人認為基於 MySQL 擴容是個問題,但是如上所說,表分完之後,RadonDB 以小表為單位做數據遷移,所以擴容非常方便。如果是加了一個新的節點,RadonDB 就會把動態的一些小表遷移到新的節點上,因為我們是基於 MySQL 做的,首先會做一個全量,然後把位點記下來,等全量做完再追增量,這個遷移過程基本不影響業務了。

所以這樣每個小表就可以在多個存儲節點上動態的漂移。這些遷移規則也可以進行自定製,比如說先遷移較大的表或者熱度比較高的表,讓整體資源分配最快達到最優化。

5

如何保障高可用?

如何打造一款 NewSQL + MySQL 的分布式数据库?

一個存儲節點內三個副本怎麼保證高可用的?我們將分佈式一致性算法 Raft 和 MySQL 自身的 GTID 結合起來。

Raft 主要做兩件事,一個是選主,第二個是數據同步。MySQL 5.7 GTID,類似於 Raft 裡面的一個 log index, 數據同步是通過 GTID,選主是通過 Raft,我們開發了一套 Raft 框架,實時監測 MySQL 狀態,如果主不正常了,就發起重新選主。

選完後新主與其他兩個從庫數據怎麼同步呢?兩個從根據自己的 GTID 向主那去拉數據,進行數據同步。MySQL 5.7 可以並行複製,過程非常迅速,主從基本沒有延遲,在高壓情況下延遲也非常小。而且,通過比較強的 semi-sync 確保事務不丟失。

存儲節點裡 Raft 和 GTID 是沒有中心化的,可以跨機房部署,非常靈活。

6

分佈式事務

下面看一下分佈式事務,為什麼分佈式數據庫需要分佈式事務呢?

因為數據在存儲節點是分佈式存儲的,比如說一個表在節點 1、節點 2、節點 3 都有存儲,然後執行了一個操作,在節點 1 成功了,在節點 2 失敗了,節點 3 成功了。這時如果沒有分佈式事務,那這個表其實是壞的。

如果沒有分佈式事務保證的話,數據隨時都處於不可用的狀態,只能用來存不重要的業務。

所以 RadonDB 就提供了分佈式事務,比如說剛才這個情況,就是 2 失敗之後,這個 1 和 3 存儲節點自動回滾,這是分佈式事務保障。

RadonDB 分佈式事務也是基於 MySQL 實現的,在 MySQL 裡面分兩階段提交。

首先它會做 xa start,然後執行 SQL,做 xa end,第四做 xa prepare,這是第一階段,此時事務才會從副本複製過去;第二個階段是 xa commit。

所以 RadonDB 在 SQL 層進行了事務管理,把 MySQL 的五個步驟抽象成三個,第一是 Begin,第二是執行,第三是提交,如果 Prepare 失敗,可以進行 Rollback。

提到分佈式事務,大家可能會問,這個事務是什麼隔離級別?

RadonDB 實現 Snapshot Isolation 也就是快照隔離級別,這是個什麼概念呢?當部分分區沒有提交時,這個事務對其他事務不可見,這就是部分提交不可見。另外就是未提交不可見,也就是說做了 prepare,但沒有 Commit,那也是不可見的。

7

SI 隔離級別

如何打造一款 NewSQL + MySQL 的分布式数据库?

大家可以看一下上圖右邊兩個 SQL 語句,兩個 Client 連上來,一個 Client 是掃表,第二個 SQL 語句就是不停更新這個表。

對於 SI 隔離級別我們用了 XeLabs/go-jepsen ,1 個更新線程,16 掃表線程,通過 100 多億次操作和監測沒有發現問題,並且可以隨機 KILL 存儲節點主副本,這些都證明 MySQL XA 已經很強大了。

RadonDB 還支持 HTAP 混合模式,在傳統的解決方案裡,一般都是兩套系統,就是兩個端口。在需要事務和需要分析的時候,分別在兩個端口處理,中間通過ETL通道進行數據同步。

但是,在 RadonDB 裡就一個端口,如果是 OLAP 的操作,我們會自動路由到計算節點,而且 OLTP 和 OLAP 這兩個計算的資源是隔離的,互不影響。

8

性能

如何打造一款 NewSQL + MySQL 的分布式数据库?

最後看一看 RadonDB 的性能。上圖是單機 MySQL 和四個存儲節點的 RadonDB 的對比。

我們用 sysbench 16 個表、512 個線程,隨機寫了 5000 萬條數據,測試得出來的結果,RadonDB 基本上可以做到 26589 TBS,單機是 9346 TBS,可以看到在 TBS 層面 RadonDB 性能將近是單機的三倍,延遲卻只有的三分之一。

這就是分佈式數據庫的威力,性能和容量可以通過節點的增加而線性增長。

如何打造一款 NewSQL + MySQL 的分布式数据库?

張雁飛,青雲QingCloud 數據庫高級技術專家。TokuDB 內核貢獻者、維護者,TokuDB 企業級熱備工具作者。

曾就職於阿里雲數據庫內核團隊,目前為青雲QingCloud 數據庫團隊負責人,從事新一代數據庫產品 —— RadonDB 的設計與研發。

- FIN -


分享到:


相關文章: