UCloud分布式數(shù)據(jù)庫UDDB:技術(shù)實(shí)現(xiàn)
在此之前,我們介紹過UDDB的功能特性和產(chǎn)品理念,明確了產(chǎn)品的發(fā)展方向——基于數(shù)據(jù)庫中間件來做公有云上的分布式數(shù)據(jù)庫。在剛開始選擇較為簡單的工程實(shí)現(xiàn)復(fù)雜度,然后通過公有云這種互聯(lián)網(wǎng)服務(wù)的快速迭代能力和在線服務(wù)能力,不斷的提高對(duì)業(yè)務(wù)的支持度,從而覆蓋更多的業(yè)務(wù)。最終演進(jìn)為大數(shù)據(jù)時(shí)代的分布式數(shù)據(jù)庫解決方案,為互聯(lián)網(wǎng)、物聯(lián)網(wǎng)、傳統(tǒng)行業(yè)的轉(zhuǎn)型提供海量數(shù)據(jù)存儲(chǔ)、處理的在線服務(wù)。
1.UDDB的技術(shù)演進(jìn)路徑
雖然技術(shù)服務(wù)于產(chǎn)品,而產(chǎn)品的發(fā)展方向體現(xiàn)了根據(jù)客戶和市場所做的戰(zhàn)略思考,但是在執(zhí)行層面上,還只是一個(gè)模糊的目標(biāo)。因此,在技術(shù)實(shí)現(xiàn)上,需要把執(zhí)行的路徑想清楚,才能將目標(biāo)清晰地落地?;ヂ?lián)網(wǎng)創(chuàng)業(yè),強(qiáng)調(diào)的是樹目標(biāo)、定路徑、滾雪球式發(fā)展。其中,定路徑是關(guān)鍵的一環(huán):向上,必須與戰(zhàn)略規(guī)劃很好地對(duì)接;往前,每一步都要踩到點(diǎn)上。如此,才能在每一個(gè)階段創(chuàng)造價(jià)值,吸收資源,發(fā)展壯大。
執(zhí)行路徑的確定,需要回歸到客戶需求上,要深入到客戶業(yè)務(wù)中,去尋找規(guī)律和辦法。通過大量的調(diào)研,我們發(fā)現(xiàn)目前技術(shù)圈的熱點(diǎn):超大表水平拆分問題,其實(shí)并不是客戶主要的痛點(diǎn),讀寫分離和垂直分庫的需求,反而是沉默的大多數(shù)。從技術(shù)演進(jìn)的趨勢來看,水平拆分必然是分布式數(shù)據(jù)庫最終的目標(biāo)。但現(xiàn)階段水平拆分對(duì)SQL的支持度不高,導(dǎo)致為了做水平拆分,很多業(yè)務(wù)層必須要做脫胎換骨的改造。因此在數(shù)據(jù)量或性能要求還沒有到這個(gè)程度的情況下,客戶并不希望為了水平拆分做業(yè)務(wù)層的改造,而是傾向于更保守的讀寫分離和垂直分庫策略。UCloud技術(shù)團(tuán)隊(duì)基于客戶的這個(gè)訴求,最終確定了這樣一條技術(shù)演進(jìn)路徑:
- 基于數(shù)據(jù)庫中間件,用最短的時(shí)間做到一主多從讀寫分離場景下100% 兼容 MySQL,讓客戶的業(yè)務(wù)在庫表零變動(dòng)、代碼零改動(dòng)的情況下,使用上UDDB;
- 在垂直分庫場景下對(duì)MySQL的 100%兼容,讓一部分有垂直分庫需求的客戶,只需要調(diào)整好庫表位置,即可將業(yè)務(wù)接入U(xiǎn)DDB;
- 逐步完善對(duì)水平拆分的支持,在產(chǎn)品推出初期,功能對(duì)齊業(yè)內(nèi)主流數(shù)據(jù)庫中間件。后續(xù)進(jìn)一步完善對(duì)SQL和事務(wù)的支持,結(jié)合對(duì)存儲(chǔ)系統(tǒng)(MySQL)的優(yōu)化、裁減或替換,實(shí)現(xiàn)最終的產(chǎn)品目標(biāo)。
在技術(shù)演進(jìn)上,三個(gè)階段并非割裂,每一個(gè)階段目標(biāo)的達(dá)成,都為下一個(gè)階段的目標(biāo)做好鋪墊。在讀寫分離和垂直分庫場景下,實(shí)現(xiàn)對(duì)MySQL的100%兼容,核心在于構(gòu)建一個(gè)完全對(duì)齊MySQL的語法解析器,解析完成后識(shí)別SQL的操作類型,即可進(jìn)行讀寫分離;識(shí)別SQL的作用對(duì)象(庫/表/視圖),即可在垂直分庫場景下,將SQL進(jìn)行有效路由和透傳;語法解析器的完善和成熟,又為水平拆分場景下,完善語義分析、分布式執(zhí)行計(jì)劃的生成、優(yōu)化和執(zhí)行打下了基礎(chǔ)。
總之,UDDB的最終目標(biāo)就是通過該技術(shù)演進(jìn)路徑,成為一款基于Shared-Nothing架構(gòu)的分布式數(shù)據(jù)庫。
在系統(tǒng)架構(gòu)和計(jì)算模型上,數(shù)據(jù)庫中間件+MySQL節(jié)點(diǎn)的分布式數(shù)據(jù)庫解決方案和NewSQL產(chǎn)品本質(zhì)上是一回事。限于本文的主題,關(guān)于數(shù)據(jù)庫中間件和NewSQL討論,在此不作展開。
2.UDDB的技術(shù)實(shí)現(xiàn)
技術(shù)路徑的確定是將產(chǎn)品目標(biāo)進(jìn)行落地,而技術(shù)實(shí)現(xiàn)則是將技術(shù)路徑進(jìn)行落地。到了技術(shù)實(shí)現(xiàn)的層面,重點(diǎn)有兩個(gè):***是把基礎(chǔ)打好,讓產(chǎn)品的生長有一個(gè)牢靠的地基;第二是要進(jìn)行大膽創(chuàng)新,在時(shí)間和人力資源有限的情況下,通過靈活巧妙的辦法滿足客戶的需求或解決客戶的問題。
2.1UDDB的系統(tǒng)架構(gòu)
如圖所示UDDB的整個(gè)架構(gòu)主要有三大模塊:
- UDB資源池:等同于UDB產(chǎn)品的資源池, UDDB存儲(chǔ)節(jié)點(diǎn)和只讀實(shí)例直接復(fù)用處于同一可用區(qū)的UDB資源。
- 分布式數(shù)據(jù)庫中間件系統(tǒng):基于數(shù)據(jù)庫中間件技術(shù)構(gòu)建的分布式、多租戶數(shù)據(jù)庫中間件系統(tǒng)由以下幾個(gè)模塊構(gòu)成:Routerd、 Mgrd、高可用UDB實(shí)例(負(fù)責(zé)元數(shù)據(jù)和配置存儲(chǔ))、Zookeeper集群(負(fù)責(zé)決策和調(diào)度)。
- UDDB管理控制臺(tái):提供 UDDB 創(chuàng)建、管理、釋放等操作的 Web 界面。
我們可以從以下兩個(gè)方面理解該系統(tǒng)架構(gòu):
① 從左往右,以業(yè)務(wù)訪問的視角來看待該架構(gòu),可以看到:
- 客戶可以通過標(biāo)準(zhǔn)的MySQL API或者客戶端來訪問UDDB, 客戶的請(qǐng)求均發(fā)往ULB,由ULB轉(zhuǎn)發(fā)到某個(gè)中間件節(jié)點(diǎn)的Routerd模塊。
- Routerd模塊將對(duì)客戶請(qǐng)求進(jìn)行分析:
如果是DML請(qǐng)求,則在進(jìn)行處理后,直接轉(zhuǎn)發(fā)到相關(guān)的UDB節(jié)點(diǎn),然后將各UDB節(jié)點(diǎn)的返回結(jié)果進(jìn)行聚合并返回給客戶端;
如果是 DDL請(qǐng)求,則通過Zookeeper集群,將該DDL任務(wù)通知到Mgrd模塊。 由Mgrd模塊將該 DDL任務(wù)取出、處理并廣播到UDDB下所有UDB節(jié)點(diǎn)。廣播完成后,將返回結(jié)果按原路經(jīng)Zookeeper集群遞交到Routerd ,***返回給客戶端。
②從右往左,以系統(tǒng)管理的視角來看待該架構(gòu),可以看到:UDDB的創(chuàng)建過程基本等同于目前利用數(shù)據(jù)庫中間件軟件+MySQL實(shí)例+負(fù)載均衡組件來搭建一個(gè)分布式數(shù)據(jù)庫解決方案的過程。這個(gè)過程為眾多開發(fā)團(tuán)隊(duì)的研發(fā)或者DBA所熟悉, 而UDDB的管理平臺(tái)無非是對(duì)這些流程做了一個(gè)完整的封裝,把這些煩瑣的操作替換為點(diǎn)擊鼠標(biāo)即可搞定。
2.2SQL解析和路由模塊
UDDB 在架構(gòu)上注重穩(wěn)健務(wù)實(shí),而在SQL的解析和路由模塊(Routerd)的設(shè)計(jì)和實(shí)現(xiàn)上,則注重規(guī)范和專業(yè)。
Routerd的核心是一個(gè)SQL解釋器。它接收SQL語句,解析其語法和語義,確定該SQL影響哪些UDB節(jié)點(diǎn),然后將SQL轉(zhuǎn)換成子SQL并下推到相關(guān)UDB節(jié)點(diǎn)。待UDB節(jié)點(diǎn)將結(jié)果返回后,可能需要根據(jù)原始SQL的語義將結(jié)果進(jìn)行過濾聚合,最終返回到客戶端。
該 SQL 解釋器的完善程度是 Routerd 的一個(gè)重要設(shè)計(jì)指標(biāo)。SQL 解釋器越完善,則對(duì)業(yè)務(wù)的支持越好,能夠支持的客戶端就越多,從而具備更好的通用性。公有云產(chǎn)品不能限制客戶類型和使用場景,因此通用性是非常重要的指標(biāo)。
業(yè)內(nèi)不少歷史悠久的數(shù)據(jù)庫中間件,雖然穩(wěn)定可靠支撐了不少實(shí)際項(xiàng)目,但是其SQL解釋器,卻一直做得不夠好??疾鞓I(yè)內(nèi)各種數(shù)據(jù)庫中間件的源碼實(shí)現(xiàn),我們可以看到, 不少中間件的實(shí)現(xiàn)存在兩個(gè)問題:
①有的中間件沒有獨(dú)立的SQL語法解析模塊,而是直接復(fù)用其他數(shù)據(jù)庫(如SqlLite)的語法解析器,或者開源SQL解析庫(如alibaba druid)。短期內(nèi),這種做法的確能夠讓項(xiàng)目迅速得以推進(jìn),但是后續(xù)功能的擴(kuò)展卻往往受制于該SQL語法解析器,因此不利于產(chǎn)品的長期發(fā)展。
②有的數(shù)據(jù)庫中間件有獨(dú)立、規(guī)范的語法解析器,但是在語義解析上做的不夠?qū)I(yè),這些中間件一般的解析流程如圖:
這樣雖然也能夠讓中間件工作,但是SQL的生成和結(jié)果的過濾聚合,都依賴抽象語法樹(AST)來完成。然而AST結(jié)構(gòu)復(fù)雜,攜帶信息也有限,使用AST來做SQL的生成和結(jié)果的過濾聚合,一方面會(huì)帶來編程上的復(fù)雜度;另一方面也不能執(zhí)行一些復(fù)雜的操作,比如 group by、order by、distinct、limit和集函數(shù)同時(shí)存在的SQL語句的聚合操作,因此很難實(shí)現(xiàn)通用性和可擴(kuò)展性。
如何做好Routerd的通用性? 可以從兩個(gè)方面著手:
***是基于Lex&Yacc構(gòu)建一個(gè)獨(dú)立、規(guī)范的語法解析模塊。讓研發(fā)團(tuán)隊(duì)做到對(duì)SQL語法圖和SQL語法解析實(shí)現(xiàn),做到了如指掌。這樣才能在有Bug時(shí)迅速修復(fù),需要添加新功能時(shí)能夠立即支持。
第二是采用類似數(shù)據(jù)庫系統(tǒng)實(shí)現(xiàn)的方式,來實(shí)現(xiàn)Routerd的語義解析。如大家所知,通用的數(shù)據(jù)庫系統(tǒng),執(zhí)行一條SQL有規(guī)范的流程如圖:
流程可以概括為語法解析、生成執(zhí)行計(jì)劃、執(zhí)行計(jì)劃優(yōu)化(查詢優(yōu)化)和執(zhí)行4個(gè)步驟。每一個(gè)步驟能夠很好地解耦,步驟之間通過約定的數(shù)據(jù)結(jié)構(gòu)來交互。這些數(shù)據(jù)結(jié)構(gòu)中,執(zhí)行計(jì)劃是最核心的,它詳細(xì)描述了SQL的語義、涉及到哪些數(shù)據(jù)庫內(nèi)部對(duì)象以及對(duì)這些內(nèi)部對(duì)象操作的順序。
參考數(shù)據(jù)庫系統(tǒng)的SQL解釋流程,UDDB的Routerd模塊的流程是:
Routerd中的分布式執(zhí)行計(jì)劃:一方面是對(duì)抽象與語法樹結(jié)構(gòu)更加精簡、扁平的描述,讓子SQL的生成更方便;另一方面,加入SQL結(jié)果過濾聚合的控制信息,方便對(duì)UDB節(jié)點(diǎn)返回結(jié)果的提取、過濾和聚合。
經(jīng)過一年多的演進(jìn)和迭代,UDDB的分布式執(zhí)行計(jì)劃和計(jì)劃執(zhí)行在逐步完善。從最初實(shí)現(xiàn)對(duì)單表SQL,以及落到同一節(jié)點(diǎn) 的JOIN SQL的100%支持,到支持多表跨節(jié)點(diǎn)Join、分布式事務(wù)這兩個(gè)核心功能(分布式事務(wù)功能目前內(nèi)測中,跨節(jié)點(diǎn)JOIN計(jì)劃于2018年上半年推出)。實(shí)踐證明,通過合理的架構(gòu),能夠讓UDDB從一款簡單的中間件出發(fā),走向更開闊的未來,成為基于MySQL并保留MySQL原生部署和運(yùn)維體驗(yàn)的,真正的分布式數(shù)據(jù)庫。同時(shí),引入和數(shù)據(jù)庫內(nèi)核同樣的架構(gòu),這意味著還可以添加執(zhí)行計(jì)劃優(yōu)化的環(huán)節(jié),對(duì)分布式執(zhí)行計(jì)劃進(jìn)行優(yōu)化,最終不僅在功能上對(duì)齊單機(jī)數(shù)據(jù)庫,在性能上也有不斷優(yōu)化的空間。
2.3讀寫分離模式100%兼容MySQL
接下來我們將給出讀寫分離100%兼容MySQL的一個(gè)創(chuàng)新性的技術(shù)實(shí)現(xiàn)供業(yè)內(nèi)參考。垂直分庫實(shí)現(xiàn)對(duì)MySQL DDL、DML語法的100%支持,其原理也類似,在本文中不做贅述。
如果做一款單純的讀寫分離中間件, 在這款中間件中做到100%SQL兼容并不難。 只需要對(duì)SQL做輕量的解析,識(shí)別SQL的是讀SQL還是寫SQL,然后使用透傳的方法透傳到主從節(jié)點(diǎn)即可:
作為一種描述性語言,SQL的語法有一個(gè)非常明顯的規(guī)律:最前面的單詞必然是操作行為(動(dòng)詞), 后面是操作對(duì)象(名詞)和限制條件。而從操作行為即可完全判斷出該SQL的讀/寫類型(call 存儲(chǔ)過程除外,因?yàn)榇鎯?chǔ)過程可寫可讀)。因此只需要提取前面幾個(gè)單詞,即可做正確的路由。
通過這兩個(gè)流程可以看到讀寫分離和水平分表兩種模式,在技術(shù)實(shí)現(xiàn)上的一個(gè)矛盾:讀寫分離假定所有的表都是不拆分的普通表, 需要提取SQL中的動(dòng)作語義來識(shí)別讀寫SQL,繼而將SQL進(jìn)行透傳; 而水平分表模式下,則需要提取SQL中的作用對(duì)象,識(shí)別到底是哪幾張表,然后進(jìn)行表名的改寫(必要時(shí)也進(jìn)行其他子句的改寫)。兩者提取信息的邏輯沒有交集,導(dǎo)致兩種模式無法有機(jī)結(jié)合。
2.4UDDB的技術(shù)創(chuàng)新
1. 修改語法解析模塊:在解析SQL生成抽象語法樹的同時(shí),將SQL中的庫表名稱提出到一個(gè)鏈表中。 假如語法解析器足夠規(guī)范,那么必然會(huì)有一個(gè)或幾個(gè)非終結(jié)符用于歸約SQL中的庫表名稱。此時(shí),可以在這些非終結(jié)符對(duì)應(yīng)的語義動(dòng)作代碼中,增加將庫表名稱保存到鏈表的操作:
2. 在語法解析之后獲得抽象語法樹以及鏈表,然后掃描鏈表,依次取出該SQL涉及的庫表名稱,結(jié)合中間件的元數(shù)據(jù)信息,判斷這些表是普通表還是水平分表。如果都是普通表,則將該SQL按照讀寫類型透傳到主節(jié)點(diǎn)或從節(jié)點(diǎn);如果是水平分表,則再進(jìn)行語義分析、執(zhí)行計(jì)劃生成和計(jì)劃執(zhí)行。
通過以上兩步,做到讀寫分離模式下,SQL接近100%的兼容以及讀寫分離模式和水平分表模式在一個(gè)產(chǎn)品中***共存。 這其中的關(guān)鍵點(diǎn)在于語法解析模塊:需要實(shí)現(xiàn)一個(gè)規(guī)范完整并且能夠和MySQL官方對(duì)齊的語法解析模塊,有了該模塊即可做到對(duì)所有SQL都能夠進(jìn)行語法解析,在解析過程中進(jìn)行庫表提?。煌瑫r(shí), 需要精心設(shè)計(jì)該語法解析模塊,將所有SQL的庫表子句,抽象為特定的幾個(gè)非終結(jié)符,從而方便植入庫表提取代碼。
該方法的優(yōu)點(diǎn)在于性能和實(shí)現(xiàn)上的簡單:庫表的提取,充分復(fù)用了語法解析過程,沒有額外的開銷;庫表類型(普通表/水平拆分的大表)的判斷,則只需要掃描提取出的庫表鏈表即可完成,性能開銷幾乎可以忽略不計(jì);實(shí)現(xiàn)上也非常簡單,總共不超過150行代碼。
3.結(jié)語
本文介紹了UDDB的技術(shù)演進(jìn)路徑及其背后的系統(tǒng)架構(gòu)技術(shù)實(shí)現(xiàn)原理,以幫助客戶解決單機(jī)MySQL中的問題、讓客戶業(yè)務(wù)運(yùn)行更順暢為宗旨。結(jié)合UCloud高水平的數(shù)據(jù)庫內(nèi)核開發(fā)能力,打造了一個(gè)結(jié)構(gòu)規(guī)范、實(shí)現(xiàn)工整的數(shù)據(jù)庫中間件,具備獨(dú)立完整的語法解析、語義解析、執(zhí)行計(jì)劃生成和計(jì)劃執(zhí)行模塊;我們不斷解決MySQL的兼容性問題,目前已經(jīng)支持所有的MySQL客戶端管理工具,包括PhpMyAdmin、Navicat、SequelPro等。2018年上半年,我們將實(shí)現(xiàn)對(duì)分布式事務(wù)和分布式Join的原生支持,從而完成對(duì)存儲(chǔ)、事務(wù)以及SQL執(zhí)行三大塊的分布式化,最終成為既保留MySQL原生部署和運(yùn)維體驗(yàn),又徹底解決單機(jī)MYSQL容量和性能問題的真正的分布式數(shù)據(jù)庫。