如何打造一流的查詢引擎,構建優秀的數據倉庫?

FreeWheel,一家專注於高端視頻廣告投放、監測、預測、增值等關鍵解決方案的企業,由於一些複雜的業務需求,引入了數據倉­­庫以便實現更多功能。在這期間,FreeWheel 也靠自身實力開發出了不少里程碑式的產品與功能。InfoQ 有幸專訪到 FreeWheel Query Engine 平臺負責人崔揚,以及 FreeWheel 大數據平臺技術專家王澍,由他們來共同揭祕:如何打造一個一流的查詢引擎服務並基於此構建出優秀的數據倉庫。

在挑戰中不斷演進

在採訪的一開始,我們先對 FreeWheel 大數據團隊進行了簡單地瞭解。

崔揚介紹了 FreeWheel大數據平臺目前的三個研發方向:第一是像 HBase、Hadoop 這樣的大數據平臺技術;第二是數據處理流水線;第三就是崔揚所在的 Query Engine 團隊,作爲公司數據檢索的首要入口點,支撐着整個公司的數據查詢需求和服務。這三個方向都是建設數據倉庫的基石。

而 Query Engine 是 FreeWheel 大數據基礎架構平臺下的一支技術團隊。

從公司的架構設計方向來說,前兩者對應用開發者努力做到透明化,Query Engine 則是有意暴露給用戶的服務。公司的各個團隊可以通過這一平臺自由實現自己的需求, 比如建設公司的數據倉庫, 構建自己的數據產品, 甚至是以交互形式做一些探索式的數據分析等等。崔揚告訴記者,團隊目前有兩個主要的技術方向:一是基於 Presto 架構的查詢服務,二是基於 Spark Streaming 的實時流處理服務。

爲什麼選擇 Presto?

在 Query Engine 團隊創立之初, 框架與工具的選型是經過了一番深思熟慮的。

據介紹, FreeWheel 目前的主流計算和查詢引擎是 Presto,從大數據團隊成立之初,就已經確立了使用 Presto 作爲重度依賴工具,並一直沿用至今。 那麼 FreeWheel 爲什麼會選擇 Presto 呢?

王澍告訴記者,和一般的數據倉庫不太一樣,Freewheel 的業務日誌結構非常複雜,整個 Schema 有各種各樣的嵌套結構,很多計算經常需要從一個日誌中的某一行的一個列表中展開來進行。藉助於 Presto,可以在一定程度上解決由 Schema 過於複雜帶來的使用上的問題。

王澍表示,Presto 的一個優點是提供了比較方便的插件式的擴展,可以實現自己的 Connector,來處理如何去查詢數據的這部分邏輯。比如,現在有一個比較新的 metric,但是怎麼算並不是很確定,這個時候就比較適合先用 Presto 去實現,作爲探索性的嘗試,避免反覆更新 Schema。同時這個 Connector 也可以屏蔽一些由於 Schema 演進所帶來的對應用的影響。這個時候 Presto 的可用性是很高的。

其次,大部分關係型數據庫傾向於用索引去做優化,但是如果數據量非常大,並且經常變化的時候,利用索引優化並不是那麼現實,因爲在更新的時候,更新索引的開銷本就不低。使用 Presto,就可以換一個角度來解決這個問題。比如 FreeWheel 實現了一個叫 Metadata Service 的東西,主要目的是在執行查詢的時候,輔助做一部分下推工作,從而減少查詢需要掃描的數據量。

除了上述的兩點,崔揚補充說,因爲 Presto 是一款速度很快的計算引擎,也屬於偏流式的數據處理框架,因此從這個角度來說,Presto 也更適合 FreeWheel 目前的業務場景。這也就決定了,最好是可以通過類似於 Presto 的查詢引擎直接去查詢原始日誌,或者基於文件去做查詢引擎。

以上這些因素是 FreeWheel 選擇使用 Presto 作爲引擎直接去查詢原始日誌的主要原因。目前團隊的 Presto 在負責提供對 PB 級別的原始日誌的查詢服務。

Query Engine 平臺發展到如今,一直基於 Presto 努力打造高效和穩定的服務。和很多其他的公司使用 Presto 只是用於線下的數據分析不同,FreeWheel 將 Presto 完全應用到了線上的應用和服務, 甚至提供面向客戶的交互式查詢產品, 後端數據倉庫的建設也是採用基於 Presto 的解決方案。

數據倉庫建設過程中的難題與攻關

在崔揚看來,數據倉庫是一個學科,經過多年的實踐,已經有非常多的原理和相關的經驗值得借鑑,但是他告訴我們:FreeWheel 引入數據倉庫技術並不是爲了用而用。因爲在實際的數據處理和查詢的過程中遇到了一些問題,爲了更好地支撐公司整體的服務,團隊纔開始正式應用數據倉庫。

他告訴記者,在幾年前,FreeWheel 開始組建和應用大數據平臺的時候,並不是依靠數據倉庫整體的概念建設的,他說:“當時數據從 Pipeline 裏產生出來以後,採用的方法是直接通過查詢引擎去查詢原始日誌。”

但是這樣的做法帶來了一些問題。

首先,隨着原始日誌越來越大,每天會產生大規模數據。隨着使用查詢系統的用戶和需求日益增多, 其中時間跨度大的歷史數據的查詢又佔據其中很大的比例, 這樣基於目前的查詢引擎直接查原始日誌的負擔就越來越重。另一方面, 公司的主要領域是廣告系統。而廣告又是一門很複雜的業務,這種業務複雜性就決定了用於描述業務的數據結構也是極爲複雜的。

據瞭解,目前 FreeWheel 的原始日誌以統一的 Schema 來進行管理, 裏面的業務實體字段已經接近 1000 個, 還不包含經過 Pipeline 處理後加入的虛擬字段。這些字段間以網狀的形式互相關聯,很難拆分爲多個 Schema。

但是由於原始日誌包含所有的字段和數據, 而每個用戶根據自己的業務場景,也許只需要查詢其中的一部分字段,查詢引擎也無法乾淨的只讀取用戶希望使用的部分數據和字段。即使已經利用了 Parquet 這種列式存儲的特性,甚至基於 Parquet 文件建立一層自主開發的索引層 (也就是前文提到的 Metadata Service), 也無法完全避免所有查詢基於原始日誌的方式帶來的大量的資源浪費和性能開銷。

所以,團隊決定開始運用數據倉庫的理論去做數據的分層。

王澍補充了一個例子。在 Presto 層,最開始的目的是提供一種日誌級別的數據查詢,但實際上對於用戶來說,需求是兩方面的。一方面可能會需要比較詳細的數據做一些自己的分析;另一部分需求可能是要求數據的彙總力度非常非常高,比如查詢某一個廣告,在某一個時間段內的整體展示情況。因此,這就需要去設計一個比較合理的數據的處理流程或者 ETL 的流程,把比較細緻的數據,彙總到合適的粒度。

在建立公司級的數據倉庫的過程中,不僅需要面對傳統數據倉庫建設中的一些經典問題, 同時,由於 FreeWheel 本身業務的複雜性和特殊性,研發團隊還要解決一些特有問題。

從業務特點來說,FreeWheel 是幫助客戶去分析廣告投放的實際效果,用戶看到廣告,肯定會觸發一個事件,由於各種各樣的原因,這個事件發生的時間會存在不可控的因素,從而導致延遲非常大,這個時候最大的時間窗口可能會到一個月以上。

爲了迴避這種複雜場景, 一般公司對其的處理方式是比較簡單的,即不做數據回填,也就是說,當天收到的數據日誌全部會算到當天的數據統計中。但是對作爲涉及廣告及計費結算的 FreeWheel 來說,需要採取回填數據的方式,才能爲客戶提供精確的數據統計和付費對賬。如何回填歷史數據,也是團隊面臨的比較大的問題。針對這種場景,研發團隊設計了一套流程,從而達到先把數據切分成獨立的時間段,再根據每個時間段去更新,進而分段彙總的效果。

而由此引發的新問題是:當天日誌數據中包含的歷史數據是呈一種很強烈的衰減趨勢分佈的,距離當天越近的日期,數據會越多,反之數據則會更少。

回填的歷史日期的數據,以獨立的文件形式存在,這樣就會存在非常多細碎的小文件。數據倉庫的 ETL 任務粒度越細,小文件就越多。海量小文件帶來的一個嚴重問題就是:Presto 對其的查詢性能下降會比較嚴重。而業務場景決定了,研發人員會很難找到一個明確的時間點,以該時間點爲切點將之前日期的數據文件做離線合併成大文件的操作。

另外,FreeWheel 對數據的精確度要求非常高,如果數據出現了誤差,即使是百萬分之一的誤差,都需要重新計算。而如果一旦將分區下的文件合併在一起,就無法再簡單地支持重刷某日當天的數據。針對這種場景,FreeWheel 也研究出了一套兼容重刷數據而又可以合併文件的方案,可以極大提升查詢的效率。

另一個存在的問題是:當數據倉庫的聚合層表以及主題層表生產出來後, 線上 BI 工具會使用 Presto 直接基於這兩層的數據提供對外的服務。但是某些 BI 工具的 SQL 建模及優化實現得並不完美,查詢性能問題比較嚴重。以下面的代碼爲例:

select 
    t.a,t.b,sum(t.c)
from 
    (select 
        a,b,c
    from 
        aggregate
    where 
        dt >= ‘2018-10-01’and dt <= 2018-11-01’
    ) t
left join 
    d_table
on
   t.a = d_table.a
group by t.a,t.b

這種查詢會先將一個月的數據全部讀取出來,做完 join 後纔會做 group by。如果能將 group by 下推到子句中執行, 這樣就可以只需要將聚合後的結果數據做 join 操作,數據量會小很多倍,執行效率也會提升非常多倍。

針對此,研發團隊修改了 Presto 的 optimizer 的源碼,加入了類似 Aggregation Push Down 的優化,總體性能有數十倍的提升。

上圖中是 FreeWheel 針對第一款基於 Query Engine 的產品進行性能優化的結果。可以看到,70% 的查詢有 10 倍以上的速度提升,有 20% 的查詢甚至有 100 倍的性能提升,優化的效果非常好。據介紹,目前 FreeWheel 對 Presto 優化器的改進點主要有三個:Partial Aggregation Push Down,Broadcast Join 和 TopN Optimization,其中後面兩處優化在 presto 後續的版本中也得到了社區的重視。

崔揚告訴我們,團隊在不斷建設貼切公司業務場景的數據倉庫的實踐過程中, 解決了非常多的問題,也積累了非常多的經驗,同時對於數據倉庫未來的發展方向也有了更清晰的規劃。

打造優秀的查詢引擎服務

回顧 Query Engine 團隊的發展,崔揚認爲有這樣三個關鍵的階段:

  • 2017 年中的時候,團隊將 Presto 升級到了 0.184 的版本,崔揚說:“這個版本相當於現在 FreeWheel 的 Presto Cluster 的基石,我們現在所有的查詢都是基於這個版本來做的。”
  • 2017 年底到 2018 年初,FreeWheel 團隊已經開始使用數據倉庫整體的建設,並完整支持了第一個基於整體大數據查詢引擎的業務需求。
  • 2018 年年初到年中,團隊把整個引擎遷移到 AWS 以後,結合目前公司的現狀開發了一套管理所有 Presto 集羣的服務,稱爲 Presto Service Manager。據介紹,這套服務主要的工作其實就是幫助維護和管理整體的 Presto 的集羣。

在長期的探索和不斷歷練的過程中,FreeWheel 在查詢引擎方面積累了大量可貴的經驗,也逐漸擁有了核心的技術競爭力。

FreeWheel 的數據經過 Pipeline 實時處理之後,會存放到 HBase 中,之後會提供兩條分支供用戶根據不同場景使用不同時間流的數據:一條分支是作爲實時查詢的解決方案, 團隊實現了基於 Presto 的 HBase Connector, 直接對 HBase 中的實時數據進行查詢;另一條分支是以小時爲粒度定時將 HBase 的數據轉存到文件存儲系統, 這些文件都是以 Parquet 的格式進行組織。

之後研發團隊又實現了基於 Parquet 文件讀取的 Presto Connector, 使用 Presto 查詢這部分歷史數據。這兩條分支的數據集都是原始日誌,它們可以無縫拼接在一起,提供給用戶以完整的數據流視圖。

Presto 提供實時 + 離線數據的完整數據流視圖

到如今,FreeWheel 的大數據平臺全線遷移到雲服務平臺。Query Engine 團隊更是借力雲平臺獨有的優勢,實現和提供了更加靈活和輕便的服務。

遷移到 AWS 雲平臺後, FreeWheel 爲什麼沒有用 AWS 的託管服務如 Athena, 甚至是 EMR, 而是選擇使用 EC2 搭建和維護自己的 Presto 集羣呢?

針對這個疑問, 崔揚解釋說:“我們針對社區版本的 Presto 做了深度的定製,同時另外還實現了兩套 Presto Connector 以滿足我們的業務場景。而 EMR 提供的 Presto 版本是社區的官方版本,無法運行我們自己的定製版本,所以 EMR 是不能滿足我們的需求的。未選擇 Athena 也是類似的問題。當然,當最上層的聚合表生產出來後,由於數據量變得相對較小,這種場景下是可以考慮使用 Athena 的。不過從目前我們針對效率和開銷的對比來看,我們自己提供的 Presto 會相較 Athena 來說會更合適一些。”

此外,FreeWheel 根據目前的業務需求,結合雲平臺非常突出的彈性能力的特點,自主開發了一套管理 Presto 集羣的服務,之又爲每個業務場景獨立運行和管理一個 Presto 集羣,相當於做了業務層面的資源隔離。

王澍解釋說:“我們現在的業務場景裏,有十幾套 Presto 集羣,並且集羣的規模和整體的數量是要不斷的增長的。如何能很快速地幫用戶部署一套集羣,或者管理一套集羣,而且能夠隨着用戶的需求伸縮這個集羣的規模?這就需要有一套服務框架能幫助我們去管理所有的服務和集羣。這就是我們做的 Presto Service Manager,是 FreeWheel 演進歷程中一個里程碑式的產品。”

Presto Service Manager 功能視圖

Presto Service Manager 實現了自動化運維集羣的功能,它可以自動檢測到新集羣的創建和老集羣的銷燬,做一些註冊和清理工作;同時,它可以自動檢測或者推斷出集羣裏某些 worker 是否處於不正常的狀態,然後自動將不正常的 worker 踢出集羣,並換入新的 worker 進來。

Presto Service Manager 還可以自動根據集羣的負載情況,自動進行 scale out 和 scale in 的動作,使 Presto cluster 具備自動的伸縮能力以應對高峯流量,並且提供了 API 的方式,允許應用方通過程序調用的方式創建 / 銷燬或者伸縮集羣。

Query Engine 團隊的未來規劃

歷經千辛萬苦,數據倉庫已經構建成形並已收穫成效,但是,還有幾個明顯的問題需要繼續改進。

王澍說,最主要的問題,也是很多數據倉庫都會面臨的一個問題是:數據模型如果比較固定,業務上的一丁點變化就會對內部造成非常大的改動,如何去權衡模型的靈活性,業務與需求之間的差異可能目前處理的還不是很好。他進一步解釋說,比如說會有一張特別寬的表,但在實際使用的時候發現,集中的 Metrics 和 Dimension 都會集中在幾組上,這就是過度設計的問題。

第二,基於業務特點,如果在數據回填期間出現了一些問題需要重新計算部分數據,這時候如何去更新歷史上的一批數據,一直是一項棘手的問題,因爲發生問題的原因多種多樣,需要改的東西也是連鎖式的。

崔揚則認爲,因爲之前查詢引擎重度依賴 Presto,所以很多業務上的邏輯直接集成到 Presto 的查詢引擎或者查詢流程過程中,這樣的做法是會和 Presto 之間有一定耦合。他告訴記者,之後的思路和方向是想把這部分與業務耦合的功能模塊從 Presto 剝離出來,形成一個獨立的模塊。這樣可以讓更多的查詢引擎複用這部分邏輯代碼。這樣相當於多條腿走路,多重保障。

王澍和崔揚也簡單地談了談他們對於構建一個優秀數據倉庫的看法與經驗。

王澍表示,一個優秀的數據倉庫的標準不少,但是最主要的一條,是如何去權衡數據倉庫設計的抽象的層次,跟實際業務需求之間變化的可能。

他解釋道,想做到任何需求都可以支持滿足,那整個數據倉庫也許只能存最明細的數據,但是這種情況下,是不太可能保證查詢的性能的,因爲所有的查詢都會反覆計算最明細的數據。如果把數據倉庫彙總到較高的層次上也許能實現查詢速度上的加速,但有細微的變化,就要重新引入一條新的 ETL 流程,去計算新的需求,如何平衡這兩點,是非常考驗設計的。

王澍認爲,建數據倉庫本身不是目的,目的是爲了滿足應用的需求,不應該把問題侷限在如何搭建數據倉庫上,而應該關注如何滿足應用的需求上。他舉例說,有一些應用查詢對於響應時間的要求非常嚴格。例如用戶在想要在頁面上,不可能等一段時間才讓結果算出來,即使數據倉庫模型再合理,計算引擎的效率非常高,算出了很多東西,但應用階段並不關心這些,用戶要一秒看到結果。所以在做數據倉庫的建設的時候,每一層應該有什麼樣的存儲結構、什麼樣的查詢引擎,都是非常重要的。

崔揚也同樣認爲,優秀的數據倉庫首先一定要滿足業務的需求,其次是數據倉庫一定要是分層,以滿足不同的查詢範圍,或者查詢的實時性要求。此外,底層的支撐框架或者支撐引擎應該多樣化的,數據倉庫也要足夠開放,可以讓用戶去按照自己的需求、給用戶一定的自由空間去做一些定製化的事情。

在問及團隊今後的方向和目標時,崔揚說:

“目前雖然團隊取得了階段性的成就,也獲得了公司及業內的認可,但是,團隊仍有很長的路要走,技術更新換代太快,追求極致的道路是無止境的。未來,我們計劃會引入分佈式緩存系統,與 Presto 結合以緩解目前使用 S3 已經遇到的性能瓶頸問題。

我們正在升級我們的 Presto 版本到最新的 0.214, 屆時會享受新版本給我們帶來的更多的新特性以及更好的穩定性。同時,我們也在探索多樣化的查詢引擎,現在 OLAP 領域內已經涌現了非常多的 SQL on Big Data 的優秀框架, 我們在不斷調研和嘗試新的技術,以期能與目前的技術框架互補。Presto 是一個相當優秀的計算框架,它仍是我們未來重要的組成部分。我們也會積極回饋 Presto 社區, 一起參與到 Presto 生態的共同建設之中。”

FreeWheel 還有大量崗位招聘中,也包括實習生崗位,歡迎大家發郵件到 [email protected] 瞭解更多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章