隨著Apache IoTDB 0.14.0-preview1 版本成功的在6.30發(fā)布,意味著IoTDB的新版分布式框架的主體功能基本完善了,當(dāng)然還有一些擴(kuò)展功能因?yàn)殚_發(fā)時(shí)間比較緊張,并未隨這次發(fā)版一起進(jìn)入,如CQ、Trigger、select into等高階功能。
這次的發(fā)版也可以稱為IoTDB分布式發(fā)展史,甚至也可以稱為IoTDB整體發(fā)展史上的一個(gè)里程碑事件。正如喬老師在我們內(nèi)部6.30的總結(jié)會(huì)上說的,這次新分布式框架奠定了IoTDB未來至少5年的基調(diào),這至少5年內(nèi),我們都不會(huì)再做框架上的大改動(dòng)了。
新版MPP查詢框架的優(yōu)勢
之前IoTDB的查詢實(shí)現(xiàn),可以說是為每種查詢手寫了最佳實(shí)現(xiàn),除了底層共用了與文件交互的SeriesReader外,幾乎每種查詢都有自己獨(dú)立的自上而下的流程。這種方式的好處在于前期查詢種類較少時(shí),每種查詢的性能都能調(diào)整到最優(yōu)。
但是隨著IoTDB的發(fā)展,查詢種類越來越豐富之后,我們發(fā)現(xiàn)原來的這種方式,擴(kuò)展性比較差,一個(gè)limit和offset的功能竟然會(huì)散落在各種查詢的內(nèi)部邏輯里,導(dǎo)致有時(shí)候做功能改動(dòng)時(shí),總會(huì)漏改某處。想新增一個(gè)查詢功能時(shí),也會(huì)有很多歷史包袱,甚至開發(fā)人員需要了解所有種類的查詢,去各個(gè)種類查詢的邏輯中修改。而新的MPP查詢框架,遵循傳統(tǒng)關(guān)系型數(shù)據(jù)庫的規(guī)則,定義出基礎(chǔ)的查詢算子,每種查詢由多個(gè)查詢算子組合而成,相比之下,新MPP的查詢框架優(yōu)勢在于:
- 添加新功能容易擴(kuò)展,算子功能更加高內(nèi)聚低耦合
a. 對于Limit功能,原來散落在各個(gè)不同類型的QueryDataSet中,現(xiàn)在就一個(gè)LimitOperator
- 統(tǒng)一計(jì)算框架、豐富謂詞條件
a. 原來select子句里的計(jì)算框架獨(dú)立于where條件里的Filter,MPP中因?yàn)橛辛薕perator和TsBlock的抽象,統(tǒng)一用TransformOperator來進(jìn)行select子句和where子句的計(jì)算
b. 以前where子句里的謂詞只支持一些簡單的二元運(yùn)算符(>, <, ==等),現(xiàn)在得益于統(tǒng)一的計(jì)算框架,無需編寫冗余的重復(fù)代碼,天然支持了更復(fù)雜的計(jì)算表達(dá)式,如where (s1 + s2) * 3 + 4 > s3
c. 之前的fill只對group by和單點(diǎn)查詢支持,現(xiàn)在因?yàn)?code>fill作為獨(dú)立的Operator,可與其他任意Operator搭配使用
- 良好的
PlanNode抽象,為后續(xù)各種查詢優(yōu)化打好基礎(chǔ)
a. 如對于limit下推,之前因?yàn)槊糠N查詢都有自己單獨(dú)的PhysicalPlan,不利于優(yōu)化規(guī)則編寫,只能把push down的代碼散落在每一處。而現(xiàn)在可以較為統(tǒng)一的編寫PushDownRule
-
統(tǒng)一不同
Operator間傳遞的數(shù)據(jù)結(jié)構(gòu)為內(nèi)存中列式存儲(chǔ)的TsBlock
可存儲(chǔ)一列時(shí)間戳、任意多列值,便于之后做各種執(zhí)行優(yōu)化(如SIMD、Operator內(nèi)改造成按列操作,提高CPU Cache命中率)。而之前不同查詢的不同階段傳遞的數(shù)據(jù)結(jié)構(gòu)不同,最底層SeriesReader向上傳遞的是按批返回的BatchData(原本是只支持一列時(shí)間戳和一列值,引入多元時(shí)間序列后,支持了一列時(shí)間戳和多列值,但多列值按行存,而非列存,結(jié)構(gòu)不統(tǒng)一);上層計(jì)算迭代時(shí),使用RowRecord按行返回。
a. 目前MPP的實(shí)現(xiàn)中因?yàn)闀r(shí)間問題,很多代碼參照了之前的老代碼編寫,導(dǎo)致部分Operator也按行返回?cái)?shù)據(jù)了(TsBlock中只有一行數(shù)據(jù)),這部分之后需要慢慢改造
- 固定查詢線程數(shù),引入優(yōu)先級(jí)和時(shí)間片的概念,查詢執(zhí)行調(diào)度更加可控與可編程。
a. 舊查詢引擎的查詢線程數(shù)雖然固定,但是沒有調(diào)度和時(shí)間片概念,先進(jìn)先出,一個(gè)查詢會(huì)一直占用一個(gè)查詢線程直到拿到FetchSize行數(shù)據(jù),這個(gè)會(huì)導(dǎo)致慢查詢長時(shí)間持有查詢線程,導(dǎo)致后面短頻快的查詢被阻塞。
- 引入背壓機(jī)制,控制查詢總內(nèi)存
a. 舊查詢引擎在查詢執(zhí)行過程中沒有內(nèi)存控制,查詢并發(fā)數(shù)上升后,很容易爆內(nèi)存;MPP框架在查詢數(shù)據(jù)傳輸處引入DataBlockManager和MemoryPool,向MemoryPool申請到內(nèi)存后,該查詢才能繼續(xù)運(yùn)行,保證查詢內(nèi)存可控。
原生分布式數(shù)據(jù)庫
這次的MPP框架也意味著IoTDB成為了原生的分布式數(shù)據(jù)庫,0.14.0-preview1中的新版單機(jī)IoTDB是由分布式IoTDB的部分組件組合而成的,這是與舊版分布式IoTDB比較大的不同。舊版分布式IoTDB將單機(jī)IoTDB作為獨(dú)立模塊,相當(dāng)于在上層做了一層中間件,去管理下層的很多IoTDB舊單機(jī)實(shí)例。舊版分布式的這種實(shí)現(xiàn)也不利于擴(kuò)展,原來開發(fā)IoTDB舊單機(jī)和舊分布式的是兩撥人,互相可能也不太了解各自模塊的實(shí)現(xiàn),導(dǎo)致一旦舊單機(jī)做了一些改動(dòng),舊分布式那邊可能就無法運(yùn)行了,需要做相應(yīng)的適配。所以這次新版分布式,我們也是將IoTDB徹底改造成了原生分布式數(shù)據(jù)庫,如此一來,就不會(huì)有之前分布式和單機(jī)之間的鴻溝了,因?yàn)槿缃竦男聠螜C(jī)只不過是分布式的一個(gè)特例罷了。
系列文章的規(guī)劃
早在我研二的時(shí)候,其實(shí)就有寫一個(gè)IoTDB查詢源碼解析的系列,但是因?yàn)楫?dāng)時(shí)IoTDB的查詢?nèi)缟鲜鏊?,?shí)現(xiàn)的太過瑣碎,很難整理成一個(gè)整體的脈絡(luò),從前到后串講起來。想要寫的話,可能每種查詢都得單獨(dú)寫一篇文章了。得益于現(xiàn)在的MPP框架,我打算寫一個(gè)系列文章《IoTDB MPP框架源碼解讀之SQL的一生》,初步打算以中國古代對各個(gè)年齡段的稱謂命名,分為襁褓(不滿周歲)、孩提(二至三歲)、黃口(十歲左右)、弱冠(二十歲)、而立(三十歲)、不惑(四十歲)、天命(五十歲)、花甲(六十歲)、古稀(七十歲)、耄耋(八十歲)、鮐背(九十歲),共11篇,具體內(nèi)容如下所示:
IoTDB MPP框架源碼解讀之SQL的一生(襁褓)——即本文,主要介紹這一系列文章的由來和概覽;
IoTDB MPP框架源碼解讀之SQL的一生(孩提)——介紹Protocol層,通過Protocol層的封裝,IoTDB能夠支持多種協(xié)議:如IoTDB原生協(xié)議、InfluxDB Protocol和MQTT等;
IoTDB MPP框架源碼解讀之SQL的一生(黃口)——介紹邏輯計(jì)劃生成
IoTDB MPP框架源碼解讀之SQL的一生(弱冠)——介紹分布式計(jì)劃生成
IoTDB MPP框架源碼解讀之SQL的一生(而立)——介紹聚合查詢在分布式計(jì)劃拆分時(shí)的細(xì)節(jié)
IoTDB MPP框架源碼解讀之SQL的一生(不惑)——介紹不同F(xiàn)ragmentInstance間交互的異步數(shù)據(jù)傳輸模塊
IoTDB MPP框架源碼解讀之SQL的一生(天命)——介紹每個(gè)FragmentInstance在DataNode上本地物理執(zhí)行計(jì)劃的生成
IoTDB MPP框架源碼解讀之SQL的一生(花甲)——介紹本地執(zhí)行計(jì)劃的運(yùn)行載體Driver的實(shí)現(xiàn)細(xì)節(jié)
IoTDB MPP框架源碼解讀之SQL的一生(古?。榻BDataNode上的查詢調(diào)度模塊
IoTDB MPP框架源碼解讀之SQL的一生(耄耋)——介紹查詢中的表達(dá)式計(jì)算的框架
IoTDB MPP框架源碼解讀之SQL的一生(鮐背)——用一個(gè)例子,將前面所有的知識(shí)串聯(lián)起來,帶領(lǐng)大家親手在IoTDB中實(shí)現(xiàn)一個(gè)查詢功能