開源分散式資料庫RadonDB的核心技術與實現

tianxiaoxu發表於2018-08-15

本文根據張雁飛在【IT168微學堂 第61期】的演講內容整理而成。

講師介紹:

張雁飛,TokuDB核心貢獻者、維護者,TokuDB企業級熱備工具作者。曾就職於阿里雲資料庫核心團隊,目前為青雲QingCloud資料庫團隊負責人,主導新一代分散式資料庫產品——RadonDB的設計與研發。

內容摘要:

RadonDB是一款將分散式一致性協議Raft與MySQL相結合的新一代分散式關係型資料庫,兼具NewSQL和MySQL兩類資料庫的優點,2018年5月10日,RadonDB在第九屆中國資料庫技術大會上正式宣佈開源。本文,RadonDB的設計者張雁飛將從架構、執行、高可用等角度,結合開原始碼為大家深度解析RadonDB的核心技術與實現。

正文演講:

RadonDB是一個開源的分散式資料庫。為什麼叫RadonDB呢?RadonDB中的Radon出自元素週期表,是一種惰性氣體,名字叫做氡。因其化學性質比較穩定,所以我們就以此來命名了這款資料庫產品。

RadonDB包含兩個部分Radon和Xenon,並不是一個簡單的資料庫中介軟體。其中,Radon類似於一個資料庫中介軟體,而Xenon是一個高可用的MySQL管理叢集工具。

上圖是RadonDB的整個架構圖,其中最上面一層是Radon,一個分散式的SQL層,負責SQL的解析和轉發。這一層就是大家說的資料庫中介軟體,它會根據使用者請求將SQL語句生成分散式執行計劃,並推到下面的儲存層。

下面這一層是Xenon,一個高可用的MySQL管理工具。在這一層的每個虛線框裡都是一“主”兩“從”的MySQL,都通過Xenon進行管理。Xenon其實是一個無中心化的管理工具,當主節點掛了之後,會使用Raft協議進行選主,選出新的“主”之後,再根據MySQL Binlog這些機制進行資料同步,從而使新的主節點繼續對外服務。

下面我們們聊一聊RadonDB的一些技術細節。RadonDB的主要功能是對使用者SQL生成分散式計劃以及執行器並行執行,當執行器下發到儲存層以後,進行ORDER BY、LIMIT、GROUP BY等二次運算。

Radon支援叢集模式,所以基本上是無狀態的。當其中一個節點掛了之後,其他節點可以很快的遷移過去,保證Radon這一層的高可用。

如果從程式碼層面來看Radon的具體工作流程,使用者SQL到達Radon之後, query.go檔案會對SQL進行語法樹的生成,生成之後根據SQL的型別進行處理。

首先,根據語法樹生成分散式的執行計劃。分散式的執行計劃是根據路由表查詢每個具體的資料分佈在哪些後端,然後生成具體的子句。

分散式執行計劃生成之後,就執行Insert executor檔案,並下發到相應節點去執行。

以上,就是RadonDB 中Radon這一層的基本工作機制。

Radon這一層還有一個比較重要的功能——分散式事務。Radon分散式事務是基於MySQL原生事務——XA事務來進行的。MySQL的XA事務在執行時可分為五個階段:第一個階段是XA START,第二個階段是SQL執行,第三個階段是XA END,第四個階段是XA PREPARE,這個階段其實資料已經通過Binlog傳到了備庫,即使主庫掛了,重建之後事務仍然處於XA PREPARE狀態,我們可以認為資料不會丟失。最後一個階段是XA COMMIT。

RadonDB對這五個階段進行了分工,共分成begin、execute、commit三個階段。

RadonDB實現了SI隔離級別的分散式事務。Radon裡有一個Commit Lock,如果不加這個鎖是實現不了這種隔離級別的。那麼什麼是SI隔離級別呢?SI是SNAPSHOT ISOLATION的縮寫,它的作用是未提交的不可見,例如有三個分割槽,當它們都沒有XA commit時,其它事務讀的時候是看不到未提交事務的資料。另一個作用是部分提交不可見,還是有三個分割槽,第一個分割槽XA commit了,其他兩個分割槽正準備commit,這時候如果有其他的客戶端讀資料也是不可見的。

為了檢測XA的隔離級別,我們研發了一個開源工具,它的思路比較簡單,就是一個更新執行緒不停地去更新,16個掃表執行緒不停地掃表。如果分散式事務滿足不了SI隔離級別,那麼16個掃表執行緒就有可能看到更新執行緒的部分資料。

我們進行了100多億次操作和檢測的測試,並且過程是隨機的。我們會把儲存層的主節點宕掉來做“主從”切換。在大量的測試中,目前還沒有發現讀取到部分資料的情況。

下面介紹一下RadonDB的另一個元件——Xenon,一個高可用的MySQL管理工具。假設一個節點有一“主”兩“從”,三個MySQL,那麼它們之間的高可用怎麼來實現呢?

Xenon的工作機制是和MySQL配合,通過MySQL連結不停地去ping MySQL,並拿到MySQL的資訊。一個MySQL對應一個Xenon,並部署在一個container裡,一“主”兩“從”分佈在不同的container裡面。當Master不可服務時,其他的Xenon會檢測不到Master發來的心跳,這時由Xenon發起的心跳會發起選主操作,進而其他的從節點會被選為新的主節點。

接下來,我們講一下Xenon如何發起選主操作、如何選擇新的主節點以及選完之後如何保證資料不丟失?

對於一“主”多“從”的MySQL叢集想要做到高可用有幾個挑戰:第一是如何選“主”;第二是選“主”之後,資料怎麼跟原先的Master進行同步,保證資料不丟失;第三是如何儘快選“主”,當原來的“主”掛了之後,新的主節點如何儘快應用資料,並對外提供服務。

我們把MySQL的GTID和Raft的選主結合了起來。Xenon主要實現了Raft選主功能,結合MySQL GTID實現高可用。瞭解Raft演算法的朋友可能都知道,Raft主要做兩件事,第一件就是選“主”。第二個就是log同步。Xenon選“主”使用了Raft選主協議,選“主”之後會結合MySQL GTID進行資料同步。

如果是一“主”兩“從”的節點,那麼這兩個從節點哪個被選為新的主?這裡結合了MySQL的GTID和semi-sync。當我們把semi-sync的vote_timeout設定為無限長,基本上就可以認為是“主”。寫完之後,至少有一個“從”會收到,然後返回給“主”,“主”再返回給cluster,這樣保證至少有一個“從”和“主”的資料是完全同步的。當“主”掛了之後,和主節點資料完全同步的從節點會被選為新的主節點,之後根據MySQL的並行複製,快速回放,並對外進行提供服務。

介紹完Radon和Xenon,我們看一下,資料在RadonDB裡面是怎麼分佈的?RadonDB的底層儲存基於MySQL,也就是說由Xenon管理的一主兩從是一個節點,整個儲存層是由多個這樣的節點組成的。

使用者建立一個表的時候需要指定一個分割槽鍵,RadonDB會根據分割槽鍵把整個大表分成32個小表。分配規則是這樣的,整個表有4096個槽位,其中每個小表是128個槽位,共有32個小表。

RadonDB的最小單位就是小表,命名為T1_0000到T1_0031,每個小表都是佔128個槽位,例如第一個小表是從0到127。這樣當使用者在做Insert時,就可以依據此判斷資料會落在哪個小表裡。

RadonDB如何做擴容呢?RadonDB最小單位是一個小表,但4096和128這兩個數字是可以配置的。在擴容上,RadonDB可以讓小表在不同的機器間動態漂移。因為是MySQL表,所以把小表從一個MySQL例項上飄到另外一個MySQL例項比較簡單。首先是做一個全量遷移,記下當時遷移的位點,然後再對增量進行追加。這種以小表為遷移的方式不但不影響讀寫操作,而且操作方便,既可以擴容,還可以縮容。

RadonDB還支援Binlog,為什麼?因為RadonDB是一個分散式資料庫,如果有別的資料庫或資料想訂閱RadonDB資料,那麼就可以訂閱RadonDB Binlog。連上RadonDB之後,執行SHOW BINLOG EVENTS,指定從哪個GTID開始,同時還可以指定訂閱多少條。這樣就可以把RadonDB資料實時的匯入到異構的資料庫裡。

如果RadonDB收到了比較複雜的AP操作,例如JOIN,它的機制又是怎麼樣的呢?RadonDB還有一個計算節點,當使用者SQL上來之後,RadonDB如果發現裡面有比較複雜的JOIN等AP操作,會自動的把這個請求路由到計算節點上。

計算節點是外掛式的,它可以是其他比較強大的AP分析型資料庫,計算節點把結果計算完之後,RadonDB會自動的反饋給客戶端,在這種情況下,客戶端是無法感知到這些操作的。

這樣做的好處是事務型和計算型是資源隔離的,但缺點是儲存需要兩份。如何克服缺點呢?其實目前我們也沒有很好的辦法,只是通過壓縮暫時的解決了這個問題。

RadonDB還實現了審計日誌功能,當使用者的請求到達RadonDB之後,RadonDB把使用者請求記錄到本地磁碟上。我們可以通過上圖中的多個維度進行審計,同時還可以查詢慢操作。當日志請求量比較大時,RadonDB會定期進行清理。同時RadonDB還支援多種審計模式,例如只讀審計、只寫審計、讀寫審計等等。

大家可能會比較擔心分散式資料庫灌進了大量資料就很難匯出來了。針對這種情況,RadonDB提供了匯入和匯出的工具,這些工具是並行式的,匯入/匯出的速度比MySQL原生的Mydumper還快。

RadonDB提供了全鏈路的監控,如果分散式資料庫是一個黑盒,那麼出了問題就很不容易排查。RadonDB從前往後做了三層監控,第一層就是show processlist,這層是監控使用者到RadonDB的連線,跟MySQL是一樣的。其中RadonDB實現了一個序列表,這一層的作用就是可以看到cluster到RadonDB執行的SQL語句。第二層是監控RadonDB內部峰值事務執行到哪個階段,大家可以通過show txnz命令進行監控;最後一層就是show queryz,這個命令可以看到具體的子句在哪些後端執行。

通過這三層監控就可以很快的定位到具體問題,比如一個慢MySQL,它到底是慢在哪些地方。

上圖是效能對比表,上面的RadonDB是四個儲存節點,下面是單機MySQL。大家可以看到,RadonDB的效能基本上是單機的三倍,而延遲基本上是1/3。為什麼會出現這種情況呢?這就是分散式的威力。假設我們有一個1TB的表,如果使用單機資料庫,那麼Btree會比較高,而且每次請求的IO深度路徑也會比較長。而RadonDB會把1TB的資料分成四個節點,假設平均每個節點是250G,每個節點還有細分每個小表。當使用者請求時,我們只需請求小表,而且RadonDB對所有的請求都是並行執行的,時間完全取決於最慢的小表。所以在這種設計中,RadonDB的效能基本上會是單機的三倍,而延遲是1/3。

最後說一下RadonDB的展望,大家都瞭解類似於Google Spanner這種NewSQL會是一個大趨勢,而且很多公司也都在完全自主研發NewSQL。有人都認為傳統的基於MySQL分庫分表的方式已經過時了,而我們提出了一個新的概念——MyNewSQL,就是MySQL和NewSQL相結合。

其實RadonDB就是一個MyNewSQL,它把NewSQL領域裡常用的演算法都拿到了MySQL裡,從而實現了MyNewSQL。RadonDB 最後實現的功能和NewSQL基本無異,但它是基於MySQL進行儲存,表、資料結構都可以是異構的,效能上也有很大的提升。

一個分散式資料庫的技術其實是非常繁瑣的,通過這篇文章是不可能完全講清楚的,但好在RadonDB已經開源,大家可以去GitHub上檢視原始碼。

RadonDB的GitHub地址:https://github.com/Radondb

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31137683/viewspace-2200083/,如需轉載,請註明出處,否則將追究法律責任。

相關文章