景萇弘, 劉文潔, 高錦濤, 裴歐亞
(西北工業(yè)大學(xué) 計(jì)算機(jī)學(xué)院, 陜西 西安 710072)
OLTP系統(tǒng)以小的事務(wù)以及小的查詢?yōu)橹鳎到y(tǒng)評(píng)估主要看其每秒執(zhí)行的Transaction以及Execute SQL的數(shù)量。一般而言,單個(gè)數(shù)據(jù)庫(kù)每秒處理的Transaction往往超過(guò)幾百個(gè),或者是幾千個(gè),Select 語(yǔ)句的執(zhí)行量每秒幾千甚至幾萬(wàn)個(gè)。
OLAP系統(tǒng)也叫DSS決策支持系統(tǒng),即數(shù)據(jù)倉(cāng)庫(kù)。由于一條語(yǔ)句的執(zhí)行時(shí)間可能會(huì)非常長(zhǎng),讀取的數(shù)據(jù)也非常多,所以不采用執(zhí)行量作為考核標(biāo)準(zhǔn),考核的標(biāo)準(zhǔn)通常是磁盤子系統(tǒng)的吞吐量(帶寬),如能達(dá)到多少M(fèi)B/s的流量。
HTAP數(shù)據(jù)庫(kù)(hybrid transaction and analytical process,混合事務(wù)和分析處理)是Gartner在2014年提出的新型應(yīng)用程序框架,打破了OLTP和OLAP之間的隔閡,既可以應(yīng)用于事務(wù)型數(shù)據(jù)庫(kù)場(chǎng)景,亦可以應(yīng)用于分析型數(shù)據(jù)庫(kù)場(chǎng)景,實(shí)現(xiàn)實(shí)時(shí)業(yè)務(wù)決策。這種架構(gòu)可以避免繁瑣且昂貴的ETL操作,而且可以更快地對(duì)最新數(shù)據(jù)進(jìn)行分析,從而成為企業(yè)的核心競(jìng)爭(zhēng)力之一。
雖然OLTP和OLAP的考核標(biāo)準(zhǔn)不一樣,但2種業(yè)務(wù)都是金融的核心需求,特別是在大數(shù)據(jù)背景下,如果能基于相同的數(shù)據(jù)存儲(chǔ)運(yùn)行2種業(yè)務(wù),將大大降低構(gòu)建OLAP數(shù)據(jù)倉(cāng)庫(kù)的成本,提高數(shù)據(jù)的應(yīng)用價(jià)值。
CBase是西北工業(yè)大學(xué)和交通銀行自主研發(fā)的面向金融應(yīng)用的分布式關(guān)系數(shù)據(jù)庫(kù)[1],基于阿里巴巴的分布式數(shù)據(jù)庫(kù)OceanBase,已經(jīng)在交通銀行上線應(yīng)用。目前CBase主要面向OLTP業(yè)務(wù),不支持OLAP業(yè)務(wù)。因此針對(duì)歷史數(shù)據(jù)的查詢、分析及統(tǒng)計(jì)則需要重新進(jìn)行數(shù)據(jù)的導(dǎo)入導(dǎo)出,利用其他分析引擎如Spark進(jìn)行分析統(tǒng)計(jì)。為了更好地支持分析業(yè)務(wù),并復(fù)用現(xiàn)有的存儲(chǔ)引擎,需要研究在CBase之上添加OLAP的查詢引擎,為分析業(yè)務(wù)提供支持。
為此,本文提出了一種基于分布式數(shù)據(jù)庫(kù)CBase的HTAP方案,在CBase和Spark之間建立一個(gè)適配層,將CBase與Spark分析引擎結(jié)合起來(lái),實(shí)現(xiàn)OLTP與OLAP功能,并對(duì)適配層的數(shù)據(jù)傳輸進(jìn)行優(yōu)化,提高AP分析效率。
數(shù)據(jù)庫(kù)系統(tǒng)一般可以按照負(fù)載類型分成操作型數(shù)據(jù)庫(kù)(operational support system)和決策型數(shù)據(jù)庫(kù)(decision support system)。操作型數(shù)據(jù)庫(kù)主要用于應(yīng)對(duì)日常流水類業(yè)務(wù),即面向消費(fèi)者類的業(yè)務(wù);決策型數(shù)據(jù)庫(kù)主要應(yīng)對(duì)的是企業(yè)報(bào)表類、可視化等統(tǒng)計(jì)類業(yè)務(wù),即面向企業(yè)類的業(yè)務(wù)。
在目前的HTAP數(shù)據(jù)庫(kù)研究中,出現(xiàn)了許多原生HTAP數(shù)據(jù)庫(kù),所謂原生,就是在同一集群中,可以同時(shí)完成OLTP與OLAP的分析工作。
BatchDB是一種為混合OLTP和OLAP工作負(fù)載設(shè)計(jì)的內(nèi)存數(shù)據(jù)庫(kù)引擎[2]。該系統(tǒng)可有效處理具有強(qiáng)大性能隔離功能的OLTP和OLAP混合工作負(fù)載。 BatchDB依賴于主次復(fù)制形式,其中主副本處理OLTP工作負(fù)載,并且更新傳播到處理OLAP工作負(fù)載的輔助副本。可以從OLAP副本的OLTP副本中高效地提取并應(yīng)用更新,從而給整體執(zhí)行時(shí)間帶來(lái)很小的開(kāi)銷。
L-Store是一個(gè)基于譜系的存儲(chǔ)架構(gòu)[3],旨在處理OLTP和OLAP的混合工作負(fù)載,并且支持多個(gè)L-Store節(jié)點(diǎn)提供可伸縮性和彈性。此系統(tǒng)通過(guò)引用新穎的、基于譜系的存儲(chǔ)體系架構(gòu),在單個(gè)統(tǒng)一引擎中結(jié)合了事務(wù)處理和分析工作負(fù)載的實(shí)時(shí)處理,以事務(wù)一致的方式開(kāi)發(fā)了一種無(wú)競(jìng)爭(zhēng)的懶惰的列數(shù)據(jù)分階段從寫優(yōu)化(適用于OLTP)到讀優(yōu)化形式(適用于OLAP)的方法。
DL-Store是一個(gè)分布式的HTAP數(shù)據(jù)處理引擎[4],DL-Store是在L-Store的基礎(chǔ)上提出的基于分布式譜系的數(shù)據(jù)存儲(chǔ)系統(tǒng),旨在處理分布式環(huán)境中的大量更新工作負(fù)載,DL-Store將數(shù)據(jù)進(jìn)行分區(qū),并將數(shù)據(jù)分布在許多L-Store節(jié)點(diǎn)上。此系統(tǒng)的設(shè)計(jì)彌補(bǔ)了以往數(shù)據(jù)存儲(chǔ)系統(tǒng)的不足,引入基于譜系的存儲(chǔ)體系結(jié)構(gòu),該體系結(jié)構(gòu)可在本機(jī)多版本的列存儲(chǔ)模型上實(shí)現(xiàn)無(wú)競(jìng)爭(zhēng)的更新機(jī)制,以便將穩(wěn)定的數(shù)據(jù)從寫入優(yōu)化的列布局(即OLTP)中延遲并獨(dú)立地轉(zhuǎn)移到讀取優(yōu)化的列布局(即OLAP)。
TBase是騰訊數(shù)據(jù)平臺(tái)團(tuán)隊(duì)在開(kāi)源的PostgreSQL基礎(chǔ)上研發(fā)的企業(yè)級(jí)分布式 HTAP 數(shù)據(jù)庫(kù)管理系統(tǒng),具備高性能可擴(kuò)展的分布式事務(wù)能力,支持RC和RR 2種隔離級(jí)別。TBase把OLTP和OLAP處理進(jìn)行融合,在一套數(shù)據(jù)庫(kù)系統(tǒng)中同時(shí)完成2種操作,降低業(yè)務(wù)復(fù)雜度和業(yè)務(wù)成本。通過(guò)資源隔離技術(shù),TBase實(shí)現(xiàn)了HTAP中關(guān)鍵的資源隔離技術(shù),同時(shí)實(shí)現(xiàn)了HTAP方案。
這些原生的HTAP數(shù)據(jù)庫(kù)均有同樣的特點(diǎn):所有的OLTP與OLAP工作都在一個(gè)集群中完成,在進(jìn)行OLAP分析時(shí),難免會(huì)影響OLTP的性能。因此,進(jìn)行了研究后,出現(xiàn)了許多集成第三方平臺(tái)的HTAP研究。
相比于這些原生HTAP數(shù)據(jù)庫(kù)而言,本文設(shè)計(jì)的分布式數(shù)據(jù)庫(kù)CBase的HTAP方案通過(guò)構(gòu)建一個(gè)適配層,并且完成與第三方數(shù)據(jù)分析平臺(tái)的連接,可以有效地將上層的數(shù)據(jù)計(jì)算平臺(tái)與底層的數(shù)據(jù)存儲(chǔ)平臺(tái)分離開(kāi)來(lái),在進(jìn)行OLAP分析的同時(shí)對(duì)OLTP的影響降至最低,既方便維護(hù),又可以減少開(kāi)發(fā)成本,提高可擴(kuò)展性。
由于在同一集群中同時(shí)進(jìn)行了OLTP與OLAP工作會(huì)對(duì)性能造成影響,因此,出現(xiàn)了許多集成第三方平臺(tái)的HTAP數(shù)據(jù)庫(kù),通過(guò)集成Storm、Flink及Spark等平臺(tái)來(lái)實(shí)現(xiàn)OLAP分析。
TiDB是一款開(kāi)源、云原生、MySQL兼容的分布式數(shù)據(jù)庫(kù),通過(guò)自研的TiSpark接口將 OLTP和OLAP功能相結(jié)合,采用一份存儲(chǔ)同時(shí)處理OLTP & OLAP,避免了傳統(tǒng)繁瑣的ETL過(guò)程,可以處理混合事務(wù)和分析處理(HTAP)工作負(fù)載。
Wildfire是一個(gè)用于大數(shù)據(jù)的HTAP系統(tǒng)[5],使用可擴(kuò)展Spark API和用于SQL查詢的Catalyst優(yōu)化器來(lái)實(shí)現(xiàn)了本系統(tǒng)的HTAP。對(duì)Wildfire的所有請(qǐng)求均通過(guò)Spark API。集群中的大多數(shù)節(jié)點(diǎn)僅執(zhí)行分析請(qǐng)求,僅需要普通服務(wù)器硬件。其他功能更強(qiáng)大的節(jié)點(diǎn)具有更快的本地持久性存儲(chǔ)和更多的內(nèi)核,可提高并行性,同時(shí)處理事務(wù)和分析查詢這些節(jié)點(diǎn)中的數(shù)據(jù)流。
過(guò)去的HTAP數(shù)據(jù)庫(kù)系統(tǒng)把所有數(shù)據(jù)都存在主存中,來(lái)實(shí)現(xiàn)同時(shí)處理OLTP和TiDB,為了降低占用空間而不影響性能,是一種混合優(yōu)化主存數(shù)據(jù)庫(kù),通過(guò)把冷數(shù)據(jù)分配到較少開(kāi)銷的次分配空間中。使用負(fù)載驅(qū)動(dòng),以Pareto-optimal allocations算法為基礎(chǔ),同時(shí)使用了再分配數(shù)據(jù)成本模型,可以決定哪些數(shù)據(jù)允許保留在主存中,以此來(lái)提高HTAP系統(tǒng)的分析效率。
T-plotter是協(xié)調(diào)OLAP和OLTP模型的新數(shù)據(jù)結(jié)構(gòu)[6],可促進(jìn)數(shù)據(jù)重建和對(duì)多個(gè)不同結(jié)構(gòu)的索引訪問(wèn)。該結(jié)構(gòu)通過(guò)實(shí)現(xiàn)數(shù)據(jù)的垂直碎片化來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)系統(tǒng)的OLAP分析功能,垂直片段化是一種用于在集中式或分布式體系結(jié)構(gòu)中有效執(zhí)行OLAP模型的技術(shù),該技術(shù)用于調(diào)用表中的某些列,有效提高了OLAP查詢效率。
由于第三方平臺(tái)有很多選擇,面向流式的開(kāi)源數(shù)據(jù)處理框架包括Storm、Flink及Spark等,要對(duì)這些框架進(jìn)行分析,選擇出適配CBase的數(shù)據(jù)處理框架。在Storm中,需要設(shè)計(jì)一個(gè)實(shí)時(shí)計(jì)算結(jié)構(gòu),這個(gè)結(jié)構(gòu)會(huì)被提交至集群,master節(jié)點(diǎn)為worker節(jié)點(diǎn)分配代碼,所有的worker節(jié)點(diǎn)負(fù)責(zé)對(duì)數(shù)據(jù)進(jìn)行計(jì)算分析。而Storm框架一次只能處理一個(gè)數(shù)據(jù)流,效率相對(duì)較低[7-11]。
Flink框架是針對(duì)流數(shù)據(jù)和批數(shù)據(jù)的計(jì)算框架,實(shí)現(xiàn)了批數(shù)據(jù)的處理[9]。但在工程實(shí)現(xiàn)時(shí),不同的job可能被分配在同一個(gè)進(jìn)程內(nèi),會(huì)影響其他job的穩(wěn)定性,對(duì)AP分析結(jié)果會(huì)產(chǎn)生誤差,最終影響設(shè)計(jì)方案的測(cè)試結(jié)果。Apache Spark不像Storm那樣一次處理一個(gè)數(shù)據(jù)流;相反,在處理數(shù)據(jù)流之前它會(huì)對(duì)數(shù)據(jù)流進(jìn)行分段切分,并生成相應(yīng)的RDD(彈性分布式數(shù)據(jù)集),可以通過(guò)任意函數(shù)或窗口進(jìn)行轉(zhuǎn)換,實(shí)現(xiàn)計(jì)算的并行操作[8,10-11]。其次,Spark不會(huì)出現(xiàn)job的進(jìn)程分配問(wèn)題,不會(huì)影響job執(zhí)行的穩(wěn)定性。因此,本文設(shè)計(jì)方案選擇Spark API作為上層數(shù)據(jù)計(jì)算框架。
本文對(duì)分布式數(shù)據(jù)庫(kù)的HTAP設(shè)計(jì)更簡(jiǎn)便且容易實(shí)現(xiàn),省去了一系列嵌入及維護(hù)工作,直接在下層通過(guò)適配層連接Spark節(jié)點(diǎn),通過(guò)適配層將所有緩存數(shù)據(jù)傳輸至各個(gè)Spark節(jié)點(diǎn),即可進(jìn)行AP分析。本文設(shè)計(jì)方案的實(shí)現(xiàn)彌補(bǔ)了當(dāng)前CBase對(duì)OLAP分析功能的缺失,并且為所有Spark節(jié)點(diǎn)的數(shù)據(jù)存儲(chǔ)提供了空間。同時(shí),各個(gè)組件之間是相互獨(dú)立的,適配層與最下層的CBase相互剝離,且與最上層的Spark分析API相互剝離,并不會(huì)由于某個(gè)組件的版本更新或者換代后,發(fā)生無(wú)法識(shí)別或宕機(jī)的后果,獨(dú)立性極強(qiáng)。為使用后的維護(hù)提供了便捷的保障。
CBase可以劃分為4個(gè)模塊:主控服務(wù)器RootServer、更新服務(wù)器UpdateServer、基準(zhǔn)數(shù)據(jù)服務(wù)器ChunkServer以及合并服務(wù)器MergeServer。
CBase內(nèi)部按照時(shí)間線將數(shù)據(jù)劃分為基準(zhǔn)數(shù)據(jù)和增量數(shù)據(jù),基準(zhǔn)數(shù)據(jù)是只讀的,所有的修改更新到增量數(shù)據(jù)中,系統(tǒng)內(nèi)部通過(guò)合并操作定期將增量數(shù)據(jù)融合到基準(zhǔn)數(shù)據(jù)中。CBase整體架構(gòu)如圖1所示。

圖1 CBase總體架構(gòu)
·客戶端
客戶端是用戶和CBase交互的接口,使用方式和MySQL數(shù)據(jù)庫(kù)相同,支持SQL交互以及JDBC和ODBC交互。
·RootServer
管理集群中的所有服務(wù)器,Tablet數(shù)據(jù)分布以及副本管理。RootServer一般為一主一備,主備之間數(shù)據(jù)強(qiáng)同步。
·UpdateServer
存儲(chǔ)CBase系統(tǒng)的增量數(shù)據(jù)。UpdateServer一般為一主一備,目前在每個(gè)集群內(nèi)部,同一時(shí)刻只允許主UpdateServer提供寫服務(wù)。
·ChunkServer
存儲(chǔ)OceanBase系統(tǒng)的基準(zhǔn)數(shù)據(jù)。基準(zhǔn)數(shù)據(jù)一般存儲(chǔ)2份或者3份,可配置。
·MergeServer
接收來(lái)自客戶端的SQL請(qǐng)求,經(jīng)過(guò)詞法分析、語(yǔ)法分析、查詢優(yōu)化等一系列操作后轉(zhuǎn)發(fā)給相應(yīng)的ChunkServer或者UpdateServer,并將來(lái)自多臺(tái)ChunkServer返回的結(jié)果合并后返回給客戶端。
根據(jù)CBase的架構(gòu),支持HTAP功能可以考慮3種方案:
1) Spark通過(guò)JDBC連接到CBase;
2) Spark直接分析CBase導(dǎo)出的CSV文件;
3) 分析TiSpark的功能類推到CBase。
第一種方案為Spark通過(guò)JDBC連接到CBase,進(jìn)行持久化及全表遍歷操作后,對(duì)CBase中的數(shù)據(jù)進(jìn)行AP分析。此方案的優(yōu)點(diǎn)是JDBC連接方法簡(jiǎn)單高效,且分析的數(shù)據(jù)具有一定的實(shí)時(shí)性,保證了數(shù)據(jù)的可靠;缺點(diǎn)是預(yù)處理操作有些繁瑣,但并不妨礙最終的結(jié)果。
Spark通過(guò)JDBC連接CBase的操作十分簡(jiǎn)單,可以使用簡(jiǎn)單的方法將數(shù)據(jù)從CBase上遷移到Spark做數(shù)據(jù)分析,使數(shù)據(jù)庫(kù)的數(shù)據(jù)分析與事務(wù)處理分別處于不同的引擎上。
第二種方案為Spark直接分析CBase導(dǎo)出的CSV文件。此方案的優(yōu)點(diǎn)是Spark分析CSV文件操作較為簡(jiǎn)單,但要保證AP分析效率,文件內(nèi)的數(shù)據(jù)也應(yīng)進(jìn)行上述的持久化和全表遍歷操作。CBase自身具有數(shù)據(jù)的導(dǎo)入導(dǎo)出功能,基于此項(xiàng),可以將需要進(jìn)行AP分析的數(shù)據(jù)導(dǎo)出為CSV文件,Spark對(duì)這些CSV文件進(jìn)行數(shù)據(jù)分析。但是由于導(dǎo)出的CSV文件是以select語(yǔ)句作為數(shù)據(jù)導(dǎo)出的基準(zhǔn),數(shù)據(jù)的過(guò)濾及其他操作必須在導(dǎo)出過(guò)程完成,導(dǎo)出后的CSV文件無(wú)法按照過(guò)濾規(guī)則等進(jìn)行更改。
雖然Spark讀取CSV文件操作簡(jiǎn)單,但Spark與CBase并未直接建立連接,是一個(gè)斷層。并且CBase數(shù)據(jù)庫(kù)數(shù)據(jù)導(dǎo)出的消耗及數(shù)據(jù)讀取的時(shí)延都是不可避免的,并且由于是直接讀取數(shù)據(jù)文件,只能整個(gè)文件完全讀取,不能進(jìn)行filter以及聚合下推等操作,數(shù)據(jù)的過(guò)濾以及分析需要完全由Spark執(zhí)行,對(duì)于Spark內(nèi)存的要求會(huì)非常高,并且將數(shù)據(jù)分析的所有壓力都推及Spark計(jì)算引擎,會(huì)明顯降低Spark分析的性能與效率。
CBase導(dǎo)出的CSV文件實(shí)際上是從ChunkServer中導(dǎo)出的歷史數(shù)據(jù),并不是一種實(shí)時(shí)數(shù)據(jù)。若是對(duì)于實(shí)時(shí)性沒(méi)有十分嚴(yán)格的要求,就可以通過(guò)導(dǎo)出歷史數(shù)據(jù)為CSV文件進(jìn)行數(shù)據(jù)分析,但是考慮到數(shù)據(jù)的實(shí)時(shí)性,若采用這種方法則只能分析歷史數(shù)據(jù),不能集合實(shí)時(shí)的增量數(shù)據(jù)進(jìn)行分析,則不能滿足數(shù)據(jù)分析的實(shí)時(shí)性。
由于導(dǎo)出的CSV文件中并不是實(shí)時(shí)數(shù)據(jù)而是歷史數(shù)據(jù),這并不能滿足OLAP要求的實(shí)時(shí)性。
第三種方案為分析TiSpark的功能類推到CBase中。此方案的優(yōu)點(diǎn)有很多,將TiSpark的功能類推到CBase中,既可以保證數(shù)據(jù)的實(shí)時(shí)性,又可以省掉方案一中繁瑣的預(yù)處理操作,且預(yù)估實(shí)驗(yàn)結(jié)果與此次結(jié)果并不會(huì)有很大差異;但此方案的缺點(diǎn)也很明顯,升級(jí)維護(hù)的工作量會(huì)非常巨大。
首先,如果CBase需要實(shí)現(xiàn)Spark on ChunkServer,同樣需要根據(jù)Spark 方面的接口改寫邏輯計(jì)劃、物理計(jì)劃以及某些算子的實(shí)現(xiàn),并且需要根據(jù)CBase的語(yǔ)法規(guī)則schema形式進(jìn)行類型轉(zhuǎn)換及schema轉(zhuǎn)換。CBase的數(shù)據(jù)類型與存儲(chǔ)格式完全不同,如果需要進(jìn)行數(shù)據(jù)對(duì)接必須要進(jìn)行schema的橋接。這樣做的最終目的是完成一個(gè)SQL解析的過(guò)程以及部分查詢優(yōu)化的功能。
其次,CBase需要改寫Spark SQL傳出的計(jì)劃使其適合于CBase的流程,schema的適配與自動(dòng)獲取,各種下推操作的實(shí)現(xiàn)包括過(guò)濾、謂詞下推和聚合下推(目前CBase支持的下推操作)等,但是若要完成這一薄層的構(gòu)建具有十分可觀的工作量,完成這一步類似于重新構(gòu)建CBase讀寫流程以及CBase的計(jì)劃部分,并且需要在這一層完成指定的下推操作。
最后,由于直接通過(guò)Spark接口開(kāi)發(fā),項(xiàng)目需要隨著Spark的升級(jí)換代而進(jìn)行更新,此方案的工作量巨大。因此,本次設(shè)計(jì)不選用此方案作為最終設(shè)計(jì)方案。
本次設(shè)計(jì)將方案一與方案二結(jié)合起來(lái),共同構(gòu)建出一個(gè)適配層,其功能同時(shí)滿足方案一與方案二的需求。既可以通過(guò)連接池將SQL語(yǔ)句傳送到Spark AP分析引擎中,又可以發(fā)送通過(guò)CBase導(dǎo)出的CSV文件至Spark AP分析引擎中進(jìn)行OLAP分析。
在適配層中,對(duì)SQL傳輸執(zhí)行部分做了一部分優(yōu)化,提高AP分析效率,具體設(shè)計(jì)在第3節(jié)中闡述。
綜合了2種設(shè)計(jì)方案的優(yōu)缺點(diǎn),設(shè)計(jì)了一個(gè)適配層來(lái)完成CBase與Spark之間的交互,實(shí)現(xiàn)CBase的HTAP設(shè)計(jì),數(shù)據(jù)流可以以2種形式傳送至Spark中進(jìn)行AP分析,分別為CSV數(shù)據(jù)文件及JDBC傳送SQL語(yǔ)句的方式。因此設(shè)計(jì)的總體架構(gòu)如圖2所示。

圖2 CBase的HTAP方案總體架構(gòu)
CBase是進(jìn)行OLAP操作的數(shù)據(jù)的來(lái)源,所有的數(shù)據(jù)都是存儲(chǔ)在CBase中,需要通過(guò)封裝好的Scala程序從CBase中取出放到Spark中進(jìn)行持久化處理后,方可進(jìn)行OLAP分析。
在整個(gè)架構(gòu)中,數(shù)據(jù)最初存儲(chǔ)在最底層CBase的ChunkServer節(jié)點(diǎn)中,使用TPC-H工具將測(cè)試數(shù)據(jù)導(dǎo)入至CBase中;通過(guò)封裝好的Scala程序,將所有測(cè)試數(shù)據(jù)從CBase中取出,此處的數(shù)據(jù)可以通過(guò)JDBC連接,把數(shù)據(jù)發(fā)送到Spark的master節(jié)點(diǎn)上;或者可以通過(guò)導(dǎo)出CBase的CSV文件,將CSV文件進(jìn)行隨機(jī)分片,分別發(fā)送給Spark的master節(jié)點(diǎn)中;最后Spark內(nèi)部會(huì)將所有數(shù)據(jù)進(jìn)行分片與節(jié)點(diǎn)分配,分別發(fā)送給集群中的不同worker節(jié)點(diǎn)進(jìn)行計(jì)算。
在整個(gè)架構(gòu)的中間層即為適配層,其上層結(jié)構(gòu)為Spark,下層結(jié)構(gòu)為CBase。這個(gè)適配層的作用為實(shí)現(xiàn)上層SparkAP分析引擎與下層CBase分布式存儲(chǔ)引擎的通信交互,并實(shí)現(xiàn)數(shù)據(jù)的傳輸。
適配層可以與Spark分析引擎及CBase分布式存儲(chǔ)引擎剝離開(kāi)來(lái);設(shè)計(jì)為剝離的形式可以提供維護(hù)的便捷,若將適配層的設(shè)計(jì)嵌入至Spark或CBase中時(shí),當(dāng)Spark或CBase進(jìn)行版本升級(jí)或更新時(shí),若源碼發(fā)生改變,則嵌入到Spark或CBase中的內(nèi)容同樣需要升級(jí)或更新,此種情況來(lái)看,維護(hù)需要耗費(fèi)許多精力。
在適配層中,可以通過(guò)2種形式進(jìn)行數(shù)據(jù)的傳輸。第一種為CSV文件的傳輸。CBase可以將某個(gè)數(shù)據(jù)庫(kù)中的所有數(shù)據(jù)導(dǎo)出至指定的CSV文件中,通過(guò)適配層可以將CSV文件分片傳送至Spark節(jié)點(diǎn)中,而后通過(guò)master節(jié)點(diǎn)的分配將分片傳送至相應(yīng)的worker節(jié)點(diǎn)中進(jìn)行AP分析工作。由于CSV文件不需要進(jìn)行JDBC連接池的連接,此種方式在傳輸效率中表現(xiàn)較好。第二種方式為執(zhí)行的SQL通過(guò)JDBC連接池傳送至Spark的master節(jié)點(diǎn)中。在此方式中,可以實(shí)現(xiàn)執(zhí)行SQL的傳輸,且在此部分中實(shí)現(xiàn)了opt優(yōu)化組件。由于Spark SQL組件的SQL語(yǔ)法解析與CBase的SQL語(yǔ)法解析有一定的差距,所以有些SQL語(yǔ)句需要進(jìn)行語(yǔ)法解析及下推操作的變換,而opt優(yōu)化組件可以實(shí)現(xiàn)這一點(diǎn),將CBase傳送的SQL語(yǔ)句轉(zhuǎn)化為可以完美適配Spark SQL的SQL語(yǔ)句。并且,此優(yōu)化組件可以指定數(shù)據(jù)行按range切分,且根據(jù)元數(shù)據(jù)保存的分布信息與指定數(shù)據(jù)行的數(shù)據(jù)建立精準(zhǔn)的連接,同時(shí)減少了網(wǎng)絡(luò)傳輸?shù)拈_(kāi)銷,提高了傳輸效率和AP分析效率。在后文的測(cè)試部分,本文僅選用了第二種方式來(lái)完成CBase的HTAP方案的實(shí)現(xiàn),由于CSV文件存儲(chǔ)的并不是實(shí)時(shí)數(shù)據(jù),而是歷史數(shù)據(jù),不能保證數(shù)據(jù)的實(shí)時(shí)性,相對(duì)于第一種方案而言,第二種方案符合實(shí)際的業(yè)務(wù)需求,因此后文的實(shí)驗(yàn)均使用第二種方案即JDBC來(lái)進(jìn)行。
Spark和CBase各有特點(diǎn),CBase作為一款成熟的分布式數(shù)據(jù)庫(kù),可以為數(shù)據(jù)存儲(chǔ)提供穩(wěn)定有效的服務(wù),所有AP分析所需數(shù)據(jù)均可以存儲(chǔ)在CBase的ChunkServer中,待需要時(shí)取出通過(guò)JDBC傳送至Spark中即可進(jìn)行相應(yīng)的AP分析工作。而Spark的主要功能為數(shù)據(jù)計(jì)算及分析,但其并沒(méi)有一個(gè)穩(wěn)定的數(shù)據(jù)存儲(chǔ)服務(wù)來(lái)支撐其運(yùn)轉(zhuǎn)。對(duì)于CBase而言,Spark的數(shù)據(jù)分析服務(wù)完全可以滿足其缺失的AP分析功能;且對(duì)于Spark而言,CBase的數(shù)據(jù)存儲(chǔ)可以為其提供穩(wěn)定的數(shù)據(jù)存放位置。兩個(gè)組件相互合作可以達(dá)到更好的效果。
因此,本文設(shè)計(jì)了一個(gè)適配層,用于實(shí)現(xiàn)Spark與CBase 2個(gè)組件的交互及數(shù)據(jù)傳輸。本層將Spark與CBase及本層相互剝離開(kāi),實(shí)現(xiàn)了各組件的分離維護(hù)及更新。此舉避免了由于Spark或CBase的升級(jí)換代導(dǎo)致的嵌入組件失效,且完成了部分SQL處理的優(yōu)化工作。實(shí)現(xiàn)了CBase的AP分析功能,且完善了Spark的數(shù)據(jù)存儲(chǔ),為其交互提供了穩(wěn)定的保障。
適配層的實(shí)現(xiàn)流程如圖3所示,具體步驟為:①通過(guò)JDBC將CBase與Spark連接起來(lái),若連接成功則進(jìn)行下一步操作,失敗則返回;②將每個(gè)數(shù)據(jù)表分別注冊(cè)為對(duì)應(yīng)的DataFrame;③每個(gè)DataFrame分別注冊(cè)為對(duì)應(yīng)的臨時(shí)表;④每個(gè)臨時(shí)表進(jìn)行數(shù)據(jù)的持久化操作,將所有數(shù)據(jù)持久化到內(nèi)存中;⑤若持久化成功則進(jìn)行Query的執(zhí)行并記錄執(zhí)行結(jié)果,若失敗則考慮是否為內(nèi)存不足的問(wèn)題。

圖3 HTAP方案實(shí)現(xiàn)流程圖
環(huán)境條件允許的情況下,盡可能使用內(nèi)存足夠的環(huán)境來(lái)完成。若數(shù)據(jù)量過(guò)大因此對(duì)內(nèi)存大小的要求過(guò)大的話,可以采用其他的持久化方法來(lái)完成。Spark中提供了不同的持久化策略,包括全部持久化到內(nèi)存中、全部持久化到磁盤中以及部分持久化到內(nèi)存部分持久化到磁盤中這3種不同的持久化策略。若數(shù)據(jù)量過(guò)大導(dǎo)致數(shù)據(jù)不足以全部放進(jìn)內(nèi)存中時(shí),可以采用最后一種持久化策略,即部分內(nèi)存部分磁盤的持久化方法,雖然這種持久化的效率要略低于全部持久化到內(nèi)存中,但這種策略可以有效地減少對(duì)內(nèi)存的壓力,將數(shù)據(jù)分散存儲(chǔ)到內(nèi)存和磁盤中。另一種解決方案為將所有數(shù)據(jù)進(jìn)行分批處理,然后對(duì)結(jié)果進(jìn)行合并。
本次的測(cè)試機(jī)器配置如表1所示,性能測(cè)試采用了TPC-H基準(zhǔn)的8張表和22個(gè)查詢,數(shù)據(jù)量從1G到3G增長(zhǎng),主要觀察數(shù)據(jù)增長(zhǎng)過(guò)程中性能的變化情況。

表1 測(cè)試機(jī)器配置
在CBase環(huán)境下測(cè)試時(shí),單節(jié)點(diǎn)相對(duì)于多節(jié)點(diǎn)分布式來(lái)說(shuō)執(zhí)行效率更高,因此選擇了單機(jī)部署CBase。而Spark采用了1個(gè)master節(jié)點(diǎn)和2個(gè)worker節(jié)點(diǎn)的部署策略,實(shí)現(xiàn)了分布式AP分析。由于在分布式配置的Spark中進(jìn)行AP分析會(huì)產(chǎn)生網(wǎng)絡(luò)傳輸開(kāi)銷,若在分布式配置的Spark中AP分析的效率高于單機(jī)部署的CBase的AP分析效率,則完全可以得到結(jié)論,適配層的作用是突出且明顯的。
為了保證測(cè)試環(huán)境的穩(wěn)定性,防止數(shù)據(jù)庫(kù)緩存以及操作系統(tǒng)導(dǎo)致的緩存影響實(shí)驗(yàn)結(jié)果,在導(dǎo)入數(shù)據(jù)之前要對(duì)CBase進(jìn)行rebuild操作,此操作的目的是清空數(shù)據(jù)庫(kù)中的所有數(shù)據(jù)及緩存。完成rebuild后再對(duì)所有測(cè)試數(shù)據(jù)進(jìn)行導(dǎo)入,從而保證數(shù)據(jù)庫(kù)中的數(shù)據(jù)是干凈、不冗余的。對(duì)于操作系統(tǒng)的緩存問(wèn)題,在測(cè)試前清理其余無(wú)用的進(jìn)程,保證僅有CBase與Spark相關(guān)進(jìn)程處于運(yùn)行狀態(tài),從而保證測(cè)試環(huán)境的穩(wěn)定性,并且在測(cè)試過(guò)程中會(huì)進(jìn)行多次實(shí)驗(yàn),采用試驗(yàn)的平均值來(lái)降低干擾性能的因素。
本次測(cè)試使用第一種連接方案,即JDBC連接CBase獲取數(shù)據(jù)庫(kù)中數(shù)據(jù)信息,且使用編寫Scala程序的方式提交到Spark運(yùn)行程序?qū)?zhí)行性能進(jìn)行測(cè)試。下面將對(duì)實(shí)驗(yàn)結(jié)果進(jìn)行比較分析。
3.3.1 Spark未持久化與CBase的結(jié)果對(duì)比
在將數(shù)據(jù)從CBase傳送到Spark后,需要進(jìn)行一步持久化操作,即將Spark收到的所有數(shù)據(jù),均持久化到內(nèi)存中。
首先,進(jìn)行第一版初次測(cè)試,使用內(nèi)存為16G的虛擬機(jī),實(shí)驗(yàn)數(shù)據(jù)為1G數(shù)據(jù)量,通過(guò)Spark-submit將已經(jīng)封裝好的jar包提交到Spark中運(yùn)行,此時(shí)并沒(méi)有進(jìn)行RDD的持久化到內(nèi)存的操作,且未進(jìn)行Spark-submit的參數(shù)調(diào)優(yōu),得到了Spark未進(jìn)行持久化及全表遍歷的測(cè)試結(jié)果。由于本次實(shí)驗(yàn)結(jié)果與CBase結(jié)果差距過(guò)大,所以每條SQL語(yǔ)句只進(jìn)行了3次實(shí)驗(yàn),用3次實(shí)驗(yàn)的平均值與CBase的運(yùn)行結(jié)果相比較。可以明顯看出,在未進(jìn)行持久化和全表遍歷操作的情況下,Spark的性能遠(yuǎn)不如CBase。用柱狀圖的形式來(lái)表達(dá),測(cè)試結(jié)果如圖4所示。

圖4 Spark未持久化與CBase結(jié)果對(duì)比
由圖4可以明顯看出,未進(jìn)行持久化及全表遍歷的Spark執(zhí)行SQL效率要遠(yuǎn)不如CBase,以任意一條SQL語(yǔ)句為例,未進(jìn)行持久化的Spark執(zhí)行效率及執(zhí)行時(shí)間要遠(yuǎn)遠(yuǎn)超出CBase本身的執(zhí)行時(shí)間,這違背了本文研究的初衷,因此需要測(cè)試持久化及全表遍歷后的Spark執(zhí)行效率。在下一節(jié)中將對(duì)比是否進(jìn)行持久化對(duì)Spark分析數(shù)據(jù)速度的影響。
3.3.2 Spark未持久化與持久化的結(jié)果對(duì)比
此次測(cè)試目的是比較Spark是否持久化對(duì)分析數(shù)據(jù)速度的影響,持久化過(guò)程包括全表遍歷,將所有表中的所有數(shù)據(jù)持久化到內(nèi)存中;以及提交Scala程序命令的參數(shù)調(diào)優(yōu)。以此結(jié)果來(lái)判斷是否持久化對(duì)數(shù)據(jù)分析效率的影響。
由圖4可以看出,未進(jìn)行持久化和全表遍歷得到的結(jié)果和CBase的結(jié)果相比執(zhí)行效率存在過(guò)大差異,Spark對(duì)SQL的操作時(shí)間過(guò)長(zhǎng),遠(yuǎn)遠(yuǎn)超出對(duì)實(shí)驗(yàn)結(jié)果的期望。在經(jīng)過(guò)研究與探討分析后,發(fā)現(xiàn)Spark中的load的數(shù)據(jù)并沒(méi)有存儲(chǔ)在內(nèi)存中,而是從磁盤中讀取出來(lái),再進(jìn)行分析。對(duì)此,可以將已經(jīng)load在Spark中的數(shù)據(jù)再進(jìn)行一次持久化操作,將數(shù)據(jù)轉(zhuǎn)為在內(nèi)存中存儲(chǔ),這樣再對(duì)RDD進(jìn)行Spark SQL操作,即可直接從內(nèi)存中讀取數(shù)據(jù)來(lái)進(jìn)行分析,比從磁盤中讀取數(shù)據(jù)分析花費(fèi)的時(shí)間要少很多。在進(jìn)行上述持久化和全表遍歷操作后,我們又進(jìn)行了第二次測(cè)試,得到了1G數(shù)據(jù)量的數(shù)據(jù)在Spark中執(zhí)行SQL操作的效率。
將對(duì)比結(jié)果繪制成柱狀圖表示,如圖5所示。

圖5 Spark未持久化與持久化結(jié)果對(duì)比
從圖5中可以清楚地看出,未進(jìn)行持久化和全表遍歷操作時(shí)Spark執(zhí)行SQL操作花費(fèi)的時(shí)間普遍在30 s以上,最高的甚至達(dá)到了370余秒,這個(gè)時(shí)間與SQL中的聚合函數(shù)涉及表的大小與多少有關(guān),而且每一條SQL語(yǔ)句,持久化和全表遍歷后的執(zhí)行時(shí)間均遠(yuǎn)小于未進(jìn)行持久化的執(zhí)行時(shí)間。這證明了Spark在對(duì)數(shù)據(jù)表進(jìn)行l(wèi)oad及遍歷的時(shí)間,占了提交一次任務(wù)總時(shí)間的絕大一部分比例,而這正是Spark的優(yōu)勢(shì)所在,將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,需要讀取數(shù)據(jù)時(shí)直接從內(nèi)存中讀取,這樣比磁盤讀取效率高得多。因此,在以下所有實(shí)驗(yàn)中,均采用將RDD數(shù)據(jù)持久化到內(nèi)存中和進(jìn)行全表遍歷的方法來(lái)完成測(cè)試。
由于在Spark中,對(duì)數(shù)據(jù)進(jìn)行持久化是一次性操作,即每次導(dǎo)入數(shù)據(jù)后,只需在第一次使用Spark之前對(duì)數(shù)據(jù)進(jìn)行一次持久化,即可實(shí)現(xiàn)將CBase中的數(shù)據(jù)持久化到內(nèi)存中;故將此持久化操作視為進(jìn)行測(cè)試之前的預(yù)處理操作,因此在后面的對(duì)比測(cè)試中,并未將持久化的時(shí)間計(jì)入各個(gè)Query執(zhí)行所消耗時(shí)間中。
3.3.3 1 G數(shù)據(jù)Spark與CBase的結(jié)果對(duì)比
下面將對(duì)數(shù)據(jù)量為1G的測(cè)試項(xiàng)進(jìn)行測(cè)試,每條SQL語(yǔ)句均進(jìn)行5次測(cè)試,最終計(jì)算出每條SQL語(yǔ)句執(zhí)行的平均值,測(cè)試結(jié)果,如圖6所示。

圖6 Spark與CBase 1G數(shù)據(jù)性能對(duì)比
由圖6可以清晰地看出,經(jīng)過(guò)持久化和全表遍歷后,Spark對(duì)每一條SQL語(yǔ)句的操作效率都要優(yōu)于CBase本身,相對(duì)于CBase效率的提升,最低的也有4倍左右的提升(Q13),而最高的提升達(dá)46倍(Q17)。Spark對(duì)每一條SQL語(yǔ)句執(zhí)行性能的提升與SQL語(yǔ)句本身的結(jié)構(gòu)有關(guān),有些SQL語(yǔ)句(大查詢)較多,提升較大;而有些SQL語(yǔ)句(小查詢)較多,提升較小。總體來(lái)看,Spark的性能要遠(yuǎn)遠(yuǎn)優(yōu)于CBase。
3.3.4 2G數(shù)據(jù)Spark與CBase的結(jié)果對(duì)比
下面將對(duì)數(shù)據(jù)量為2G的測(cè)試項(xiàng)進(jìn)行測(cè)試,測(cè)試步驟與1G數(shù)據(jù)量相同,測(cè)試后得出結(jié)果,并繪制出性能對(duì)比柱狀圖以方便觀察實(shí)驗(yàn)結(jié)果并進(jìn)行分析。

圖7 Spark與CBase 2G數(shù)據(jù)性能對(duì)比
從圖7可以看出,經(jīng)過(guò)持久化和全表遍歷后,Spark對(duì)每一條SQL語(yǔ)句的操作效率都要優(yōu)于CBase本身,且相對(duì)于1G數(shù)據(jù)來(lái)說(shuō),每條語(yǔ)句執(zhí)行時(shí)間無(wú)論是Spark還是CBase都要相對(duì)慢一點(diǎn)。對(duì)于大查詢Q9,CBase的查詢執(zhí)行時(shí)間甚至達(dá)到了425.444 s,而經(jīng)過(guò)持久化和全表遍歷處理后,Spark的查詢執(zhí)行時(shí)間僅為12.010 s,相比CBase本身而言縮短了35倍左右時(shí)間。提升最低的為Q16,提升了大約4倍。提升最高的為Q17,大約提升57倍。總的來(lái)說(shuō),Spark的AP性能要優(yōu)于CBase。
3.3.5 3G數(shù)據(jù)Spark與CBase的結(jié)果對(duì)比
下面將對(duì)數(shù)據(jù)量為3G的測(cè)試項(xiàng)進(jìn)行測(cè)試,測(cè)試步驟與1G、2G數(shù)據(jù)量相同,測(cè)試結(jié)果如圖8所示。
如圖8所示,經(jīng)過(guò)持久化和全表遍歷后,與1G和2G數(shù)據(jù)量的結(jié)果相同,Spark執(zhí)行每條SQL操作的效率都要優(yōu)于CBase,對(duì)于最大查詢語(yǔ)句Q9來(lái)說(shuō),CBase每次執(zhí)行Q9需要花費(fèi)平均715.562 s約12 min,這樣的效率過(guò)低導(dǎo)致分析速度過(guò)慢,對(duì)數(shù)據(jù)量更大的數(shù)據(jù)庫(kù)來(lái)說(shuō),成本太大不方便進(jìn)行大數(shù)據(jù)量的AP分析;而反觀Spark,可能在預(yù)處理操作時(shí),全表遍歷的過(guò)程會(huì)稍微花費(fèi)一點(diǎn)時(shí)間,但這種花費(fèi)是有收益的,節(jié)省了在Spark上執(zhí)行SQL語(yǔ)句的時(shí)間,且收益可觀,執(zhí)行Q9語(yǔ)句,Spark平均只用了14.594 s,是CBase執(zhí)行時(shí)間的約1/50,執(zhí)行效率有巨大提升。

圖8 Spark與CBase 3G數(shù)據(jù)性能對(duì)比
本文在CBase的基礎(chǔ)上提出了一種HTAP方案,設(shè)計(jì)了一個(gè)適配層,將上層AP分析引擎Spark與下層數(shù)據(jù)存儲(chǔ)引擎CBase相連接,實(shí)現(xiàn)了其組件間的交互,將存儲(chǔ)在CBase中的數(shù)據(jù)通過(guò)JDBC驅(qū)動(dòng)或CSV數(shù)據(jù)文件傳送至Spark節(jié)點(diǎn)中,通過(guò)提交Scala程序的方法對(duì)CBase中存儲(chǔ)的數(shù)據(jù)進(jìn)行AP分析,實(shí)現(xiàn)了CBase分布式數(shù)據(jù)庫(kù)的HTAP方案。對(duì)不同數(shù)據(jù)量測(cè)試得到結(jié)果進(jìn)行分析,結(jié)果表明:本文所提出的適配層方案可以在CBase穩(wěn)定存儲(chǔ)的基礎(chǔ)上,合理高效地進(jìn)行AP分析,且易于維護(hù),為分布式數(shù)據(jù)庫(kù)提供了可行的HTAP方案。