Presto 實踐 | Presto 高性能引擎在美圖的實踐

01
技術選型
Presto是一個Ad-Hoc的ROLAP解決方案。ROLAP的優(yōu)缺點簡單介紹如下:

POLAP優(yōu)點:
ROLAP適合非常靈活的查詢。
ROLAP查詢性能相對比較高。
ROLAP針對MPP架構(gòu)支持實時數(shù)據(jù)的寫入與實時分析。
Presto內(nèi)置支持各種聚合的算子,如sum、count,擅長計算一些指標如PV、UV,適合多維度聚合查詢。
ROLAP缺點:
所有計算和分析都是基于內(nèi)存去完成的,對內(nèi)存的需求比較大。
線上實際使用過程中發(fā)現(xiàn),查詢周期相對比較長時(如查一年、兩年的數(shù)據(jù)),經(jīng)常會遇到數(shù)據(jù)量會過大的問題,會線性影響查詢性能。
對比MOLAP由于需要提前做一次預計算,Presto則存在一定的性能差距。
MOLAP的典型技術實現(xiàn)是Druid和Kylin。兩者均通過做預計算,創(chuàng)建對應的cube,來實現(xiàn)一個性能上比較快的OLAP方案。但是,這是以犧牲業(yè)務靈活性為代價的。相比來說,Presto有更好的靈活性。
我們內(nèi)部調(diào)研了三個Ad-Hoc的ROLAP技術組件選型,包括Hive on Spark,Impala和Presto。
1. Hive on Spark

Hive on Spark的優(yōu)點,首先是在美圖內(nèi)部廣泛使用,經(jīng)受住了時間的考驗。其次是使用上的靈活性,因為已經(jīng)使用了很多年,相對比較熟悉,做過較多二次改造,包括源碼增強和一些重點模塊重構(gòu)。
缺點也是顯而易見的,Hive on Spark在查詢一些相對比較大的任務,容易發(fā)生shuffle、OOM和數(shù)據(jù)傾斜等問題。其次,Hive on Spark和其他競品如Impala和 Presto相比,查詢速度很慢,明顯無法滿足在線查詢的需求。
2. Impala

Impala的優(yōu)點,首先是輕量快速,支持近實時的查詢。其次,所有計算均在內(nèi)存中完成,減少了計算延遲和磁盤IO開銷。
但缺點也比較多,首先是主節(jié)點缺乏高可用的機制(HA機制)。其次是零容忍問題,即一個查詢發(fā)送過來的話,如果其中一個節(jié)點查詢失敗,會導致整個查詢都失敗。再次,我們在使用過程中發(fā)現(xiàn)它對自定義函數(shù)支持的不是很好。另外,Impala強依賴于CDH的生態(tài),跟我們現(xiàn)有架構(gòu)不能很好的融合。我們現(xiàn)有架構(gòu)使用了一些開源社區(qū)的組件。如果強依賴于CDH, 當我們要做版本升級、補丁升級或者代碼重構(gòu)后的升級時,存在過度依賴CDH而操作不友好的問題。最后,就是查詢數(shù)據(jù)量過大的話,會發(fā)生比較嚴重的性能下降。此外,還有對于并發(fā)的支持,不是特別好。
3. Presto

最后來看今天的主角Presto。Presto優(yōu)點首先是輕量快速,支持近乎實時查詢。其次,它的社區(qū)活躍度也比較高,文檔也比較完善,基本可以兼容業(yè)務上所有的SQL,也能扛住比較大的并發(fā)。
當然Presto也有一些缺點,一是零容忍問題,如果一個失敗,一個節(jié)點上的查詢失敗,會導致整個查詢的失敗。再就是主節(jié)點缺乏HA的機制。HA這個缺點,業(yè)界也有方案可以去完善。在下一個章節(jié),會分享美圖是如何完善HA機制的。

我們通過對比三個組件的一些特性,包括多表關聯(lián)、單表查詢和系統(tǒng)負載等,得到了一個打分。分數(shù)越高越適合我們的業(yè)務場景,優(yōu)勢越明顯。表格中可以看到,Presto總計39分是最高的,最符合我們的業(yè)務場景。

同時我們也做了計算性能上的對比。Presto的性能最好,Impala略微差一些。可能比較細心的同學會發(fā)現(xiàn),在Query 9里面,Impala的結(jié)果是空白的,這是因為Impala不兼容Query 9中的語法。這里面我們也對比了在美圖內(nèi)部用的比較多的Spark SQL,由于上篇文章沒講到Spark SQL,所以這里只做了一個性能的比較。基于這些維度考慮,我們最終選擇了Presto。

前面提到,Presto有一個比較致命的缺陷,就是缺乏主節(jié)點的HA高可用性。在這一章節(jié)中,看看我們?nèi)绾稳タ朔屯晟七@個組件。
首先,我們看一看Presto的整體流程。Presto Client端發(fā)送一個查詢請求給Presto的Coordinator, Coordinator先去Hive Metastore獲取這個任務執(zhí)行過程中所需的一些源數(shù)據(jù)信息,再將任務轉(zhuǎn)發(fā)給它對應的Worker節(jié)點,然后Worker節(jié)點從文件系統(tǒng)里面去拉數(shù)據(jù)做計算。
這個流程中,顯而易見致命的缺點是Coordinator的單節(jié)點。Coordinator故障會導致整個集群的不可用,會嚴重影響線上業(yè)務。此外,Coordinator對集群升級也帶來比較大的風險。
2. 方案
這里面整理了業(yè)界廣泛使用的兩個方案。
方案一:

方案一是多集群部署的方式,分為兩個集群,分別為Presto集群一和Presto集群二。Client端在運行任務時,會按照一定的規(guī)則去選擇某一個Presto集群,建立連接,創(chuàng)建任務。任務建立完成后,Client端將連接的Presto Coordinator會話信息保存起來,存儲在DB里面。這樣當Presto集群掛掉之后,當前會話會有一些任務失敗,在連接到新的集群之后,可以做任務恢復。最后,每一次任務進行交互的時候,都直接訪問當前獲取連接的Presto集群即可。
這個方案本身沒有問題,可以快速的搭建出一套容災方案。但是其缺點也是顯而易見的。其實只需要一套集群,但是做了過多的冗余,用了兩套集群來完成在線查詢的業(yè)務,在成本方面不能接受。當然基于這個方案,也可以在同一個機器上做混部,相當于一個機器多個Worker實例。但會存在管理難度比較大的問題,可能會涉及到Worker與Worker之間的資源搶占,終歸不是最優(yōu)的方案。
這里稍微點一下,這邊Meta Store有三臺機器,是為了實現(xiàn)高可用。Coordinator接收到任務,會去獲取任務的一些源數(shù)據(jù)信息。此時通過三個Meta Store進行輪詢選擇。當一臺Meta Store掛掉之后,還有兩個實例可以用。這個方案一被pass掉了,因為不能接受它的冗余。
方案二:

接下來看方案二,Presto采取了一個主備的Coordinator單集群部署方式。這個是大規(guī)模集群比較常見的部署方式。
首先,在Presto集群上層部署一個KeepAlived的第三方服務。然后通過KeepAlived創(chuàng)建單獨的虛擬IP(Virtual IP),指向?qū)闹鱾涔?jié)點。這樣,客戶端通過虛擬IP訪問集群,內(nèi)部Worker也通過虛擬IP訪問Coordinator節(jié)點。主節(jié)點故障時,KeepAlived通過內(nèi)部的服務注冊Discovery機制,注冊到一臺新的Coordinator上,這樣對虛擬IP的訪問會飄移至另外一臺Coordinator,同樣Worker節(jié)點也會訪問另外一臺Coordinator。
總結(jié)來說:如果Coordinator master發(fā)生了故障,可以業(yè)務無感知的切換到備用Coordinator上。這個方案可以解決我們Coordinator單點的問題,也不存在任何的資源浪費的問題。
3. 實施步驟

接下來我們再細細的看一下方案二的一個大致的實施步驟。第一,需要綁定一個通配地址,也就是類似0.0.0.0這么一個通配地址,確保能接受VIP的請求。如果是同網(wǎng)段,這樣的IP也可以, 只要他的這個網(wǎng)絡環(huán)境是互通的就可以了。
第二點就是使用KeepAlived去監(jiān)控本地的Coordinator進程。當服務發(fā)生異常時,去關閉這個KeepAlived進程,使得這個VIP可以漂移到另外一臺機器上。將Worker的Coordinator地址配置成對應的VIP,然后定期上報狀態(tài)。其實再展開一點,Worker并不是向真正的Coordinator服務上報狀態(tài),而是向Discovery這個服務去上報狀態(tài)。Discovery相當于是Coordinator的一個進程。當發(fā)生虛擬IP漂移的時候,Worker會在下一次上報狀態(tài)的時候,無感知的去注冊到新的Coordinator。Client可以繼續(xù)通過VIP去訪問集群。
可能會有點繞,大家只要記住,Coordinator和Worker都是通過這個VIP去進行關聯(lián)與信息交互。在網(wǎng)上,這個方案也相對比較成熟,具體的代碼和配置都可以找到。
03
跨集群調(diào)度

第三部分,我們來介紹一下美圖內(nèi)部跨集群調(diào)度的實現(xiàn)。這是基于我們的業(yè)務特性去做的一個優(yōu)化。我們內(nèi)部有兩套集群,其中一個為離線集群,主要就是跑一些統(tǒng)計報表,離線查詢之類的任務,另一個是Presto集群。他們存在一個資源錯峰狀態(tài),離線集群業(yè)務高峰是在凌晨的0點到9點,會將資源利用率持續(xù)打滿。Presto本身是一個在線查詢的集群,基本上凌晨沒人使用,0點到9點是它的一個業(yè)務低谷,資源利用率接近0%。這樣存在一個資源錯峰。我們想把Presto在業(yè)務低谷的這部分資源利用上。
可能大家會有個疑問,傳統(tǒng)的集群部署基本上都是從自己的HDFS去拉取數(shù)據(jù)。如果資源要互通的話,就需要去訪問各個集群上的文件,才能做下一步的計算。
2. 架構(gòu)演進

美圖在去年完成了一個上云的操作,在云上使用了存算分離的架構(gòu),實現(xiàn)了數(shù)據(jù)的統(tǒng)一存儲。這樣的好處是打破了傳統(tǒng)架構(gòu)的數(shù)據(jù)孤島的問題,離線集群和Presto集群可以無差別的訪問云上的存儲,即離線集群可以訪問到Presto集群上的數(shù)據(jù),Presto上的數(shù)據(jù)也可以訪問到離線集群的數(shù)據(jù)?;谶@兩點,我們就提出了一個跨集群調(diào)度的概念,去減輕離線集群的高峰負載,提升Presto集群凌晨業(yè)務低谷資源使用率。
在上云初期,因為有數(shù)據(jù)孤島,各自集群有各自的HDFS,數(shù)據(jù)沒法互通。如圖所示,這是上云初期架構(gòu)示意圖。在上層,是對應的大數(shù)據(jù)開放平臺,做一些臨時查詢,和一些例行任務。在下一層,是自研的一個分布式調(diào)度系統(tǒng),主要是做任務的一些日常調(diào)度。再下來,我們開發(fā)了一個檢驗層,做一些合法性的校驗。任務合法性,是指這個任務所攜帶的參數(shù)和語法,是否合法等。在這里還做了統(tǒng)一的權(quán)限校驗等數(shù)據(jù)安全的攔截。這些校驗完成之后,才會轉(zhuǎn)發(fā)給離線集群,通過Yarn去做資源調(diào)度,以及跟HDFS的交互。
3. 轉(zhuǎn)發(fā)策略

在實現(xiàn)跨區(qū)域調(diào)度之后,團隊內(nèi)部研發(fā)了一個智能內(nèi)核。智能內(nèi)核其實里面有三個比較核心的東西,一個是智能引擎,也就是和團隊現(xiàn)在一起在做的事情。跨集群調(diào)度就是通過這個任務根據(jù)評估離線集群和Presto集群的一個業(yè)務集群負載,去轉(zhuǎn)發(fā)到各自的集群,去分擔各自的集群壓力,或者說提升一個資源的利用率。這邊也實現(xiàn)了一個算力互補的這么一個東西,當然最底層是通過我們的云基建,云上存儲進行實現(xiàn)的。當然我們在評估這個轉(zhuǎn)發(fā),就是什么樣的任務可以去轉(zhuǎn)發(fā)到Presto上呢,我們也做了一些簡單的轉(zhuǎn)發(fā)策略,比如說轉(zhuǎn)發(fā)量上,我們會根據(jù)Presto集群規(guī)模,去設置一些離線任務的轉(zhuǎn)發(fā)率。
再就是轉(zhuǎn)發(fā)的時間段,需要在指定的時間段內(nèi)轉(zhuǎn)發(fā)。因為業(yè)務低峰是0點到9點,那么在9點之后,分析師同學已經(jīng)上班了,可以開始去做一些在線查詢的一些操作。那不能影響他們的業(yè)務,所以我們需要規(guī)定一個轉(zhuǎn)發(fā)時間段。還有一些任務的類型,需要判斷歷史任務的一些耗時,若耗時比較大的任務,就不適合做這個轉(zhuǎn)發(fā)。
4. 實施步驟

具體的實施步驟跟大家簡單的看一下。
首先是Hive Server服務的搭建。在離線集群上,我們用了Hive on Spark。了解過Hive on Spark的同學呢,就知道他們其實是通過Hive Server進行任務接收的。我們在Presto集群內(nèi)去搭建和部署自己的Yarn和Hive Server環(huán)境,主要是用于跨區(qū)域調(diào)度的任務、接受和執(zhí)行等。再就是,因為Hive集群的這個任務要轉(zhuǎn)發(fā)至Presto集群上運行,所以離線集群的配置也要和Presto集群做一些統(tǒng)一。
其次是用到的一些第三方包,還有一些補丁。在內(nèi)部團隊也做了比較多的代碼重構(gòu)。需要去將這些代碼去Merge到Presto的集群上,做好補丁的統(tǒng)一,還有相關告警配置,隊列資源計費統(tǒng)計。再就是一些服務開發(fā),這個服務開發(fā)主要就是用于我們的專家系統(tǒng),還有智能引擎的一些服務模塊,最后就是灰度上線。
當前面的這些環(huán)境全部都做好之后,開始灰度,灰度覆蓋率由小到大做任務的轉(zhuǎn)發(fā)。可以看一下這個收益分析。離線集群的資源在夜間它的消耗降低了10%,因為集群間已經(jīng)實現(xiàn)了算力互補,可以將離線集群的一部分機器去遷移至Presto集群上,那也相當于對Presto做一個擴容。這樣Presto的集群性能也提高了19%。
04
展望未來

最后,我們對未來進行一個展望。在大數(shù)據(jù)場景下,根據(jù)任務屬性的不同可以分為三類任務:大shuffle任務,中大型任務和小型任務。
大shuffle任務數(shù)據(jù)量非常大,查詢級別在數(shù)百億,還有比如說做多維度的cube構(gòu)建,或者grouping set類似這樣的操作,比較適合Hive on Spark運行。因為Hive on Spark是基于磁盤進行計算,穩(wěn)定性相對高。
中大型任務的數(shù)據(jù)量相對比較大,SQL語句也比較復雜,比較適合Hive on Spark或者Spark SQL。在日常使用中,我們發(fā)現(xiàn)Spark on SQL的性能明顯優(yōu)于Hive on Spark。但是,對于在這部分中大型任務,團隊內(nèi)正在嘗試使用Presto來解決時效性或者運行時間問題。
小型任務的數(shù)據(jù)量比較小,SQL也比較簡單,非常適合Presto去做。Presto對小型任務也有比較好的性能表現(xiàn)。
用一句話來總結(jié):對于中大型任務和小型任務,會將原來的Hive on Spark或者Spark SQL的運行方式,逐步切換到Presto上,來達到性能提升的目的。

目前的架構(gòu)也遇到了一些挑戰(zhàn):
比如,在離線統(tǒng)計Hive集群上,有些UDF有一些語法兼容的問題,還有一些語義差異。
比如某個任務,在離線集群上用了一個Hive UDF,在Presto上也要實現(xiàn)對應的UDF?,F(xiàn)在這個完全是靠人力去開發(fā)對應的UDF。當然,后面也在想一些更好的方式,如何去快速的適配Hive上已有的UDF。
再就是一些語法上的兼容,比如說Hive語法在Presto上去跑,它不一定能兼容。那么我們會去采集線上所有的任務,去做一個提前的預編譯,去找出語法上的一個兼容性問題,然后針對性的有選擇的去做一些改造和兼容。為什么是有選擇性呢?我們不一定會將線上所有任務都都扔到Presto上,只是有選擇性把一些中小任務放Presto上執(zhí)行。
還有就是語義的差異,我們會用Hive和Presto兩個引擎執(zhí)行,然后對比結(jié)果,針對性的做一些改造的兼容。再就是轉(zhuǎn)發(fā)策略,什么樣的任務能夠轉(zhuǎn)發(fā)到Presto上呢?我們會分析它的一個SQL語句,包括一些語法樹的分析,還有任務的輸入輸出,任務復雜度的一些分析。
最后一點,是權(quán)限校驗。我們會在客戶端層做一個基于多引擎級別的統(tǒng)一權(quán)限校驗。
Q:是否考慮過使用Doris來對接Hive,性能相比Presto會快。
A:Doris暫時沒有考慮,我們有在做ClickHouse。ClickHouse在我們內(nèi)部慢慢做起來了之后,隨著業(yè)務的接入,框架的相對比較成熟之后,也會考慮將ClickHouse接入到多引擎的這個架構(gòu)里面。所以說Doris我們現(xiàn)在沒有用。
Q:Presto在查詢大數(shù)據(jù)性能和Hive on Mapreduce差的很多嗎?可以對比一下嗎?
A:Presto在查詢中小型任務性能遠遠好于Hive on Mapreduce,但如果查詢大任務的話就不一定了,因為Presto主要基于內(nèi)存上的計算。在線上其實也發(fā)現(xiàn),如果一個任務查詢的時間周期比較長的話,拉取數(shù)據(jù)的量級也比較大,計算復雜度高。任務很可能會失敗,甚至會拖垮整個集群。所以我們會在客戶端做一定的攔截去保護,相當于一定的熔斷機制,就不讓這樣的任務發(fā)到Presto集群內(nèi)部。所以若一個非常大的查詢的話,我還是比較建議將這樣的任務去轉(zhuǎn)發(fā)到Hive on MR或者說Hive on Spark這樣的引擎上。中小型任務可以嘗試在Presto引擎上執(zhí)行。
Q:更進一步了解智能引擎是如何工作的?
A:智能引擎一個核心的概念,就是會對歷史的一些做一些分析,得到任務畫像系統(tǒng)。當任務下一次任務再運行后,會根據(jù)這個畫像系統(tǒng)里面的存儲的一些任務metric信息,去指定給我們下層的最適合的引擎,就是相當于最適合的任務交給最適合的引擎執(zhí)行。例如我們有MapReduce,Hive on Spark, Spark SQL引擎還有包括說后面會繼續(xù)引入的Presto,那么什么樣的任務適合什么樣的引擎執(zhí)行,這正是智能引擎做的事。
在文末分享、點贊、在看,給個3連擊唄~
分享嘉賓:

??分享、點贊、在看,給個3連擊唄!??
