背景及現(xiàn)狀
汽車之家是一家力求為消費者提供最新汽車報價,汽車圖片,汽車價格大全,最精彩的汽車新聞、行情、評測、導購內(nèi)容,是提供信息最快最全的中國汽車網(wǎng)站。
在公司發(fā)展過程中,之家運用了各種各樣的數(shù)據(jù)管理系統(tǒng)來存儲與管理各種各樣的數(shù)據(jù):關(guān)系型數(shù)據(jù)庫、NoSQL 數(shù)據(jù)庫、文檔數(shù)據(jù)庫、Key-value 數(shù)據(jù)庫,對象存儲系統(tǒng)等等。形態(tài)多樣的數(shù)據(jù)管理系統(tǒng)為之家在管理數(shù)據(jù)上帶來便利的同時,隨之而來的是管理與充分利用這些數(shù)據(jù)系統(tǒng)存儲的數(shù)據(jù)的難題。
無論是關(guān)系型數(shù)據(jù)庫中的MySQL,抑或是 Hadoop 體系下的 Hive,這些目前業(yè)界通用的數(shù)據(jù)管理系統(tǒng)都有自成體系的一套 SQL 方言,在之家的業(yè)務系統(tǒng)中,也運用到了這些數(shù)據(jù)關(guān)系系。
所以在之家,需求方想要分析某一種數(shù)據(jù)管理系統(tǒng)的數(shù)據(jù),就得熟練掌握某一種 SQL 方言;為了對不同數(shù)據(jù)源進行聯(lián)合查詢,就得在應用程序邏輯中使用不同的客戶端去連接不同的數(shù)據(jù)源,由之而來帶來的問題是:整個分析過程架構(gòu)復雜,編程入口多,系統(tǒng)集成困難,這對于涉及海量數(shù)據(jù)的數(shù)據(jù)分析工作變得十分痛苦。
解決方案
針對上述問題,之家調(diào)研了多種方案和技術(shù)可行性,最終選擇openLooKeng。
首先,在之家用到了RDBMS、NoSQL、Hive、MPPDB等多種類型數(shù)據(jù)倉庫,openLooKeng可以實現(xiàn)這些數(shù)據(jù)倉庫的聯(lián)合查詢。其次,利用openLooKeng的跨源異構(gòu)查詢能力,之家需求方可以快速分析海量數(shù)據(jù),從而揭示出數(shù)據(jù)背后的真相,為上層提供決策的依據(jù),指導業(yè)務發(fā)展。最后,openLookeng為開源項目,社區(qū)活躍度高,出現(xiàn)問題可以和社區(qū)共同快速解決。
關(guān)鍵特性
讓我們先來看看 openLooKeng 的一些關(guān)鍵特性,以便更深入的理解為什么open LooKeng 和之家的業(yè)務場景相符合,甚至您也可以基于 openLooKeng 的這些能力進一步探索更多的業(yè)務場景。
1. ANSI SQL2003 語法的支持
在之家的多種業(yè)務場景中,使用的是 ANSI SQL2003 語法,由于openLooKeng支持此語法,所以之家用戶使用 openLooKeng 語法進行查詢時,一方面無需改變之前查詢習慣,無差異運用。另一方面無論底層數(shù)據(jù)源是 RDBMS 還是 NoSQL 或者其他數(shù)據(jù)管理系統(tǒng),借助 openLooKeng的Connector 框架,數(shù)據(jù)可以依然存放在原始的數(shù)據(jù)源中,從而實現(xiàn)數(shù)據(jù)平滑遷移的查詢。
最后,通過 openLooKeng 的統(tǒng)一 SQL 入口,可實現(xiàn)對底層各種數(shù)據(jù)源 SQL 方言的屏蔽,之家用戶無需再關(guān)心底層數(shù)據(jù)源的 SQL 方言便可獲取到該數(shù)據(jù)源的數(shù)據(jù),方便用戶消費數(shù)據(jù)。
2. 多種多樣的數(shù)據(jù)源 Connector
在之家運用了多種數(shù)據(jù)管理系統(tǒng),openLooKeng 針對這些數(shù)據(jù)管理系統(tǒng)都有對應的數(shù)據(jù)源 Connector,包括 RDBMS(Oracle Connector),NoSQL(Hive Connector、HBase Connector 等),全文檢索數(shù)據(jù)庫(ElasticSearch Connector 等)。openLoo Keng 可以通過這些多樣的 Connector 方便的獲取到數(shù)據(jù)源數(shù)據(jù),從而進一步進行基于內(nèi)存的高性能聯(lián)合計算。
3. 高性能的查詢優(yōu)化技術(shù)
openLooKeng 在內(nèi)存計算框架的基礎上,還利用許多查詢優(yōu)化技術(shù)來滿足高性能的交互式查詢的需要。
3.1 索引
openLooKeng 提供基于 Bitmap Index、Bloom Filter 以及 Min-max Index 等索引。通過在現(xiàn)有數(shù)據(jù)上創(chuàng)建索引,并且把索引結(jié)果存儲在數(shù)據(jù)源外部,在查詢計劃編排時便利用索引信息過濾掉不匹配的文件,減少需要讀取的數(shù)據(jù)規(guī)模,從而加速查詢過程。
3.2 Cache
openLooKeng 提供豐富多樣的 Cache,包括元數(shù)據(jù) cache、執(zhí)行計劃 cache、ORC 行數(shù)據(jù) cache 等。通過這些多樣的 cache,可加速用戶多次對同一 SQL 或者同一類型 SQL 的查詢時延響應。
3.3 動態(tài)過濾
所謂的動態(tài)過濾是指是在運行時(run time)將 join 一側(cè)表的過濾信息的結(jié)果應用到另一側(cè)表的過濾器的優(yōu)化方法,openLooKeng 不僅提供了多種數(shù)據(jù)源的動態(tài)過濾優(yōu)化特性,還將這一優(yōu)化特性應用到了 DataCenter Connector,從而加速不同場景關(guān)聯(lián)查詢的性能。
3.4 算子下推
openLooKeng 通過 Connector 框架連接到 RDBMS 等數(shù)據(jù)源時,由于 RDBMS 具有較強的計算能力,一般情況下將算子下推到數(shù)據(jù)源進行計算可以獲取到更好的性能。openLooKeng 目前支持多種數(shù)據(jù)源的算子下推,包括 Oracle、HANA 等,特別地,針對 DC Connector 也實現(xiàn)了算子下推,從而實現(xiàn)了更快的查詢時延響應。
商業(yè)數(shù)據(jù)分析應用實踐
在之家的商業(yè)化廣告、線索等多個業(yè)務線,每個業(yè)務線根據(jù)不同的業(yè)務場景,分別使用不用的數(shù)據(jù)源,這些數(shù)據(jù)存儲系統(tǒng)往往相互隔離,形成相互獨立的數(shù)據(jù)孤島。當針對不同業(yè)務線的不同數(shù)據(jù)源或者同業(yè)務線的不同數(shù)據(jù)源進行聯(lián)合數(shù)據(jù)分析的時候,openLookeng起到了至關(guān)重要的作用。針對數(shù)據(jù)開發(fā)和分析師應用場景如下:
針對開發(fā)而言。針對上述業(yè)務場景,按照一般解決思路,把數(shù)據(jù)都統(tǒng)一入統(tǒng)一數(shù)據(jù)源,然后在統(tǒng)一數(shù)據(jù)源中查詢分析,導致數(shù)據(jù)鏈路長,數(shù)據(jù)完整性和時效性不能保證,數(shù)據(jù)校驗時,產(chǎn)生額外的數(shù)據(jù)驗證時間,并且驗證邏輯復雜化。引入openLooKeng后,可以直接在自帶頁面或者通過JDBC驅(qū)動的方式從JAVA訪問openLookeng,配置中增加業(yè)務數(shù)據(jù)所存儲的各種數(shù)據(jù)源,直接就可以用統(tǒng)一查詢SQL進行夸源查詢,提升開發(fā)效率。
站在分析師角度。面對海量數(shù)據(jù),如果不知道數(shù)據(jù)用在哪里、怎么用,就無法基于海量數(shù)據(jù)構(gòu)建新的業(yè)務模型。分析師對個業(yè)務線數(shù)據(jù)進行商業(yè)分析時,需要從業(yè)務數(shù)據(jù)所存儲的多個數(shù)據(jù)源中獲取數(shù) 據(jù),如RDBMS(如MYSQL,ORACLE等)或者NOSQL(如HIVE,HBASE等)。
查詢不同的數(shù)據(jù)源,需要不同的連接方式或客戶端,運行不同的SQL方言。這些差異導致額外的學習成本和復雜的應用開發(fā)邏輯,另外,每種數(shù)據(jù)源自帶的函數(shù),比如字符串函數(shù)、窗口函數(shù)、計算函數(shù)等,對應的函數(shù)名稱或者參數(shù)也不相同,所以使用時,需要分別區(qū)分處理,加大了工作量,數(shù)據(jù)錯誤率也會上升。
引入openLookeng后,提供統(tǒng)一SQL接口,自動屏蔽各個數(shù)據(jù)源語法差異,減去學習的時間,分析師商業(yè)化分析效率大大提高。
升級Apache Kylin連接器
之家商業(yè)化業(yè)務強度依賴的Kylin并沒有被openLooKeng覆蓋,openLooKeng 對Kylin數(shù)據(jù)源的支持不完善,達不到使用要求,所以我們決定升級Kylin連接器并貢獻給社區(qū)。
首先介紹下Kylin。Kylin是一個開源OLAP分析引擎,提供HADOOP之上的SQL查詢接口以及多維分析能力以支持超大規(guī)模數(shù)據(jù)。作為一款OLAP分析工具,在之家有著相當廣泛的應用,所以Kylin和其他數(shù)據(jù)源的跨源查詢需求隨之而來。
其次解釋下openLooKeng連接器(connector,以下連接器用connector代替)。connector是用于在 openLooKeng 中進行查詢的所有數(shù)據(jù)的源。即使您的數(shù)據(jù)源沒有可以支持它的基礎表,只要將您的數(shù)據(jù)源與 openLooKeng 期望使用的 API 相適配,您也可以針對這些數(shù)據(jù)編寫查詢。
最后詳細介紹對Kylin connector升級的關(guān)鍵點:
1. 元數(shù)據(jù)
Kylin元數(shù)據(jù)和其他RDBMS如MYSQL不同,它包括HIVE表的元數(shù)據(jù)和Kylin的元數(shù)據(jù),Kylin的元數(shù)據(jù)包括Project,Model,Cube,Segment多種元數(shù)據(jù)信息,所以針對Kylin元數(shù)據(jù)的操作和RDBMS相比有區(qū)別。比如獲取查詢SQL的列信息,Kylin是基于Apache Calcite來實現(xiàn)SQL解析和優(yōu)化,包括生成執(zhí)行計劃,所以對于Kylin SQL的列信息獲取基于Calcite來實現(xiàn)。如下圖:
2. SQL關(guān)鍵字
當在Kylin中查詢使用SQL關(guān)鍵字時,要加上雙引號,并且里面的內(nèi)容要大寫,這點與其他的RDBMS也不相同,需要單獨處理。如下圖:
在KylinSqlStatementWriter類中重寫select方法,對sql中的關(guān)鍵字進行特殊處理。其中處理具體規(guī)則如下:
如果Kylin中的查詢SQL語句中,對列的重命名名稱為sum、count、min、max、rank關(guān)鍵字,則將關(guān)鍵字加上雙引號,并且大寫處理。
3. SQL優(yōu)化器
在正常使用過程中,發(fā)現(xiàn)openLooKeng的優(yōu)化規(guī)則SingleDistinctAggregationGroupBy對Kylin connector不適用,因為對于Kylin而言,只有當查詢的模式和cube定義相匹配的時候,Kylin才能用對應的cube數(shù)據(jù)來完成查詢,但是對于SingleDistinctAggregationGroupBy這個規(guī)則優(yōu)化查詢之后,輸出和原有的SQL差異比較大的時候,造成匹配不上原有cube,則導致查詢不到數(shù)據(jù)。所以需要升級SQL優(yōu)化器。
3.1 介紹
下圖為openLooKeng執(zhí)行SQL的各個環(huán)節(jié),查詢語句經(jīng)過解析之后形成抽象語法樹,然后經(jīng)過Analyze生成邏輯計劃,邏輯計劃再經(jīng)過一系列的優(yōu)化規(guī)則來生成更高效的邏輯計劃,進而轉(zhuǎn)成物理計劃。在邏輯計劃優(yōu)化階段,openLooKeng提供了幾類查詢優(yōu)化器(比如基于成本的優(yōu)化,基于rule的優(yōu)化,支持table下推優(yōu)化器規(guī)則),每類優(yōu)化器提供幾十種優(yōu)化規(guī)則。
其次補充說明:SingleDistinctAggregationToGroupBy優(yōu)化規(guī)則對Kylin不適用的原因,由于SingleDistinctAggregationToGroupBy規(guī)則是對指標進行distinct的SQL優(yōu)化,優(yōu)化邏輯為將SQL轉(zhuǎn)換成group by ,然后再count計算,其實就是采用“分治”的思想來提升查詢效率,對于如下SQL:
當經(jīng)過此規(guī)則優(yōu)化之后,輸出如下:
但是優(yōu)化之后的SQL匹配不到對應cube,所以當Kylin的sql進行查詢優(yōu)化的時候,需要過濾此規(guī)則。
3.2 自定義規(guī)則方案
首先,根據(jù)上述優(yōu)化規(guī)則是針對邏輯計劃的。LogicalPlanner類就是對解析出來的抽象語法樹(AST)生成邏輯計劃,我們可以從下圖看出,planOptimizers包含了幾類優(yōu)化規(guī)則,而SingleDistinctAggregationToGroupBy是屬于IterativeOptimizer這類規(guī)則。
針對Kylin connector自定義過濾規(guī)則,有兩種方案,如下:
方案一:基于openLooKeng的下推框架,將執(zhí)行計劃樹傳遞給connector,再將PlanOpt
imizerst提供給執(zhí)行優(yōu)化引擎,這樣可以讓connector引入針對自己的任意優(yōu)化規(guī)則?;诖朔桨?,是否可以將SingleDistiAggregation ToGroupBy優(yōu)化規(guī)則在Kylin
connector中實現(xiàn)過濾。但是此框架只能增加自定義優(yōu)化規(guī)則,不能修改原有系統(tǒng)規(guī)則,如下圖,所以此方案不可行。
方案二:利用OptimizerUtils工具類提供的兩個方法,來判斷上文中系統(tǒng)自帶的優(yōu)化規(guī)則是否適用于此邏輯計劃,所以對規(guī)則的過濾是在OptimizerUtils類中實現(xiàn)。目前采用的是這種方案。
3.3 自定義規(guī)則初始化
接下來為了實現(xiàn)代碼的可擴展性和可維護性,將自定義的過濾規(guī)則配置在文件中,由于connector的連接信息已經(jīng)有獨立的配置文件,所以直接在此文件中增加配置項“blacklist”。如下圖:
下面介紹如何將新增配置項初始化到系統(tǒng)中。在主程序啟動類PrestoServer的start方法中調(diào)用StaticCatalogStore.loadCatalogs的方法來進配置和連接信息初始化。如下圖:
過濾規(guī)則初始化到OptimizerUtils類的planOptimizerBlacklist靜態(tài)變量中,如下圖;
3.4 自定義規(guī)則過濾
首先,在OptimizerUtils類的isEnabledLegacy方法中實現(xiàn)規(guī)則過濾。首先通過邏輯執(zhí)行計劃解析出SQL中的catalog列表,然后遍歷優(yōu)化器中的優(yōu)化規(guī)則,如果優(yōu)化規(guī)則在數(shù)據(jù)源catalog配置列表中,則此規(guī)則不起作用。
其次,獲取catalog列表時,由于上文提到的幾十種規(guī)則都是對于同一邏輯計劃進行優(yōu)化,所以用threadlocal維護一個解析后的線程本地變量,在同一請求中,只解析一次執(zhí)行計劃,避免重復解析,提升效率。
最后,講解如何解析邏輯計劃,由于邏輯計劃為一個計劃樹,樹上有通過解析SQL得到的節(jié)點,比如TableScanNode,ProjectNod,JoinNode,F(xiàn)ilterNode等,比如如下SQL:
對應的邏輯計劃樹為:
由于需要獲取表對應的數(shù)據(jù)源catalog,所以我們只關(guān)心TableScanNode節(jié)點,遞歸計劃樹,獲取到所有表的數(shù)據(jù)源catalog。如下圖:
總結(jié)與規(guī)劃
引入openLooKeng后,之家具備了跨源異構(gòu)的數(shù)據(jù)查詢能力,覆蓋了同業(yè)務線的或不用業(yè)務線的不同數(shù)據(jù)源的分析業(yè)務場景,提高了之家用戶數(shù)據(jù)分析效率。另外,根據(jù)之家自身業(yè)務需要,升級Kylin connector并貢獻給社區(qū),使openLooKeng的connector更加豐富,同時覆蓋了之家更多的應用。
后續(xù)我們持續(xù)關(guān)注openLooKeng社區(qū)發(fā)展,并且接入之家更多的業(yè)務和分析場景,不斷完善和持續(xù)更新迭代openLooKeng,和社區(qū)共同成長。