其實(shí)不然,MySQL 并沒(méi)有過(guò)時(shí),本篇文章的主角 —— RadonDB ,就是把 NewSQL 領(lǐng)域比較流行的分布式一致性算法和 MySQL 結合起來(lái),形成了新一代的分布式數據庫 MyNewSQL,同樣做到了可擴展、高可用、強一致、易部署的特點(diǎn)。
那么,如何將 NewSQL 領(lǐng)域比較流行的技術(shù)和 MySQL 結合起來(lái),打造一款新的分布式數據庫?

1、RadonDB 的架構
首先看一下 RadonDB 的架構,如上圖所示,上半部分是分布式的 SQL 層,下面是存儲層,如果我們對 F1 和 Spanner 進(jìn)行抽象之后,會(huì )發(fā)現也都是這兩層。
其中 SQL 層主要負責對用戶(hù) SQL 解析,然后生成分布式的執行計劃和執行器,再把這些執行器下發(fā)到具體的存儲節點(diǎn)去執行。
雖然架構看上去比較一致,但 RadonDB 比較特殊的一點(diǎn)是:下面的存儲層有多個(gè)存儲節點(diǎn)。圖中每個(gè)圓圈里面都是一個(gè)存儲節點(diǎn),每個(gè)存儲節點(diǎn)有三副本,三副本之間就是一個(gè) Raft 協(xié)議進(jìn)行數據同步,每個(gè)副本都是一個(gè) MySQL。而其他 NewSQL 就是一個(gè) KV 或者其他的存儲。
2、RadonDB 架構層解析
下面詳細闡述一下架構里面的各個(gè)技術(shù)點(diǎn)。
SQL 節點(diǎn)

首先來(lái)看一下 SQL 節點(diǎn)。
用戶(hù)請求到達 SQL 節點(diǎn)后,我們根據數據的分布規則生成一個(gè)分布式的執行計劃,告訴用戶(hù)的 SQL 要分發(fā)到哪些存儲節點(diǎn),然后根據分布式執行計劃生成一個(gè)分布式的執行器,就是具體到哪些存儲節點(diǎn)進(jìn)行鏈接、執行、返回。
執行完之后 SQL 節點(diǎn)就會(huì )做二次運算,為什么叫二次運算?因為下面是 MySQL,SQL 節點(diǎn)把計算推到 MySQL 之后,SQL 節點(diǎn)再進(jìn)行二次運算,包括 limit/groupby/aggregation/join。
所以說(shuō),SQL 節點(diǎn)是一個(gè)無(wú)中心化、無(wú)狀態(tài)的,擴容性強。
3、存儲層

存儲層由多個(gè) Node 組成,每個(gè) Node 就是一主兩從的 MySQL,但這個(gè) MySQL 比較特殊,因為 MySQL 沒(méi)有一個(gè)高可用的方案,可能大家都是 MHA 或者自己寫(xiě)一個(gè)主從切換腳本來(lái)運維。
但是 RadonDB 引入了 Raft 協(xié)議,它是無(wú)中心化的, 當主庫掛了后,通過(guò) Raft 協(xié)議選擇新主,而數據同步則基于 MySQL GTID 機制。
基于 MySQL 的好處是不僅有存儲能力還有計算能力,如果一個(gè)副本只是一個(gè) KV ,他的計算能力就比較有限,SQL 層把數據推到存儲層,然后再返回 SQL 節點(diǎn)再進(jìn)行運算,這樣存儲層和 SQL 層交互就會(huì )比較多。
我們盡量把計算能力下推到存儲層讓 MySQL 完成,因為 MySQL 跟數據是在一塊的,不涉及網(wǎng)絡(luò )傳輸,只需要幾個(gè) I/O 就將數據過(guò)濾掉了。

4、數據分布
剛才說(shuō)了 SQL 層和存儲層,再看一下數據怎么分布?
建一個(gè) T1 表,后面指定的分區方式是 HASH,在 RadonDB 里面默認整張表共 4096 slots, 每個(gè)小表默認是 128 slots, 其實(shí)就是一個(gè)大表分成 32 個(gè)小表,比如兩個(gè)存儲節點(diǎn),這個(gè) T1 表的 32 個(gè)小表,前 16 個(gè)小表在第一個(gè)存儲節點(diǎn)上,后 16 個(gè)小表是在第二個(gè)節點(diǎn)上,是均分布的。
可能很多人認為基于 MySQL 擴容是個(gè)問(wèn)題,但是如上所說(shuō),表分完之后,RadonDB 以小表為單位做數據遷移,所以擴容非常方便。如果是加了一個(gè)新的節點(diǎn),RadonDB 就會(huì )把動(dòng)態(tài)的一些小表遷移到新的節點(diǎn)上,因為我們是基于 MySQL 做的,首先會(huì )做一個(gè)全量,然后把位點(diǎn)記下來(lái),等全量做完再追增量,這個(gè)遷移過(guò)程基本不影響業(yè)務(wù)了。
所以這樣每個(gè)小表就可以在多個(gè)存儲節點(diǎn)上動(dòng)態(tài)的漂移。這些遷移規則也可以進(jìn)行自定制,比如說(shuō)先遷移較大的表或者熱度比較高的表,讓整體資源分配最快達到最優(yōu)化。
5、如何保障高可用?

一個(gè)存儲節點(diǎn)內三個(gè)副本怎么保證高可用的?我們將分布式一致性算法 Raft 和 MySQL 自身的 GTID 結合起來(lái)。
Raft 主要做兩件事,一個(gè)是選主,第二個(gè)是數據同步。MySQL 5.7 GTID,類(lèi)似于 Raft 里面的一個(gè) log index, 數據同步是通過(guò) GTID,選主是通過(guò) Raft,我們開(kāi)發(fā)了一套 Raft 框架,實(shí)時(shí)監測 MySQL 狀態(tài),如果主不正常了,就發(fā)起重新選主。
選完后新主與其他兩個(gè)從庫數據怎么同步呢??jì)蓚(gè)從根據自己的 GTID 向主那去拉數據,進(jìn)行數據同步。MySQL 5.7 可以并行復制,過(guò)程非常迅速,主從基本沒(méi)有延遲,在高壓情況下延遲也非常小。而且,通過(guò)比較強的 semi-sync 確保事務(wù)不丟失。
存儲節點(diǎn)里 Raft 和 GTID 是沒(méi)有中心化的,可以跨機房部署,非常靈活。
6、分布式事務(wù)
下面看一下分布式事務(wù),為什么分布式數據庫需要分布式事務(wù)呢?
因為數據在存儲節點(diǎn)是分布式存儲的,比如說(shuō)一個(gè)表在節點(diǎn) 1、節點(diǎn) 2、節點(diǎn) 3 都有存儲,然后執行了一個(gè)操作,在節點(diǎn) 1 成功了,在節點(diǎn) 2 失敗了,節點(diǎn) 3 成功了。這時(shí)如果沒(méi)有分布式事務(wù),那這個(gè)表其實(shí)是壞的。
如果沒(méi)有分布式事務(wù)保證的話(huà),數據隨時(shí)都處于不可用的狀態(tài),只能用來(lái)存不重要的業(yè)務(wù)。
所以 RadonDB 就提供了分布式事務(wù),比如說(shuō)剛才這個(gè)情況,就是 2 失敗之后,這個(gè) 1 和 3 存儲節點(diǎn)自動(dòng)回滾,這是分布式事務(wù)保障。
RadonDB 分布式事務(wù)也是基于 MySQL 實(shí)現的,在 MySQL 里面分兩階段提交。
首先它會(huì )做 xa start,然后執行 SQL,做 xa end,第四做 xa prepare,這是第一階段,此時(shí)事務(wù)才會(huì )從副本復制過(guò)去;第二個(gè)階段是 xa commit。
所以 RadonDB 在 SQL 層進(jìn)行了事務(wù)管理,把 MySQL 的五個(gè)步驟抽象成三個(gè),第一是 Begin,第二是執行,第三是提交,如果 Prepare 失敗,可以進(jìn)行 Rollback。
提到分布式事務(wù),大家可能會(huì )問(wèn),這個(gè)事務(wù)是什么隔離級別?
RadonDB 實(shí)現 Snapshot Isolation 也就是快照隔離級別,這是個(gè)什么概念呢?當部分分區沒(méi)有提交時(shí),這個(gè)事務(wù)對其他事務(wù)不可見(jiàn),這就是部分提交不可見(jiàn)。另外就是未提交不可見(jiàn),也就是說(shuō)做了 prepare,但沒(méi)有 Commit,那也是不可見(jiàn)的。
7、SI 隔離級別

大家可以看一下上圖右邊兩個(gè) SQL 語(yǔ)句,兩個(gè) Client 連上來(lái),一個(gè) Client 是掃表,第二個(gè) SQL 語(yǔ)句就是不停更新這個(gè)表。
對于 SI 隔離級別我們用了 XeLabs/go-jepsen ,1 個(gè)更新線(xiàn)程,16 掃表線(xiàn)程,通過(guò) 100 多億次操作和監測沒(méi)有發(fā)現問(wèn)題,并且可以隨機 KILL 存儲節點(diǎn)主副本,這些都證明 MySQL XA 已經(jīng)很強大了。
RadonDB 還支持 HTAP 混合模式,在傳統的解決方案里,一般都是兩套系統,就是兩個(gè)端口。在需要事務(wù)和需要分析的時(shí)候,分別在兩個(gè)端口處理,中間通過(guò)ETL通道進(jìn)行數據同步。
但是,在 RadonDB 里就一個(gè)端口,如果是 OLAP 的操作,我們會(huì )自動(dòng)路由到計算節點(diǎn),而且 OLTP 和 OLAP 這兩個(gè)計算的資源是隔離的,互不影響。
8、性能

最后看一看 RadonDB 的性能。上圖是單機 MySQL 和四個(gè)存儲節點(diǎn)的 RadonDB 的對比。
我們用 sysbench 16 個(gè)表、512 個(gè)線(xiàn)程,隨機寫(xiě)了 5000 萬(wàn)條數據,測試得出來(lái)的結果,RadonDB 基本上可以做到 26589 TBS,單機是 9346 TBS,可以看到在 TBS 層面 RadonDB 性能將近是單機的三倍,延遲卻只有的三分之一。
這就是分布式數據庫的威力,性能和容量可以通過(guò)節點(diǎn)的增加而線(xiàn)性增長(cháng)。
作者簡(jiǎn)介

張雁飛,青云QingCloud 數據庫高級技術(shù)專(zhuān)家。TokuDB 內核貢獻者、維護者,TokuDB 企業(yè)級熱備工具作者。
曾就職于阿里云數據庫