presto架構(gòu)和原理分析

架構(gòu)

架構(gòu)

Presto查詢引擎是一個Master-Slave的架構(gòu),由一個Coordinator節(jié)點,一個Discovery Server節(jié)點,多個Worker節(jié)點組成,
Discovery Server通常內(nèi)嵌于Coordinator節(jié)點中。
Coordinator負責解析SQL語句,生成執(zhí)行計劃,分發(fā)執(zhí)行任務給Worker節(jié)點執(zhí)行。
Worker節(jié)點負責實際執(zhí)行查詢?nèi)蝿铡?/p>

Worker節(jié)點啟動后向Discovery Server服務注冊,Coordinator從Discovery Server獲得可以正常工作的Worker節(jié)點。如果配置了Hive Connector,需要配置一個Hive MetaStore服務為Presto提供Hive元信息,Worker節(jié)點與HDFS交互讀取數(shù)據(jù)。

  • 主從架構(gòu)
  • Coordinator
  • Worker
  • Discovery Server

執(zhí)行過程

提交查詢

用戶使用Presto Cli提交一個查詢語句后,Cli使用HTTP協(xié)議與Coordinator通信,Coordinator收到查詢請求后調(diào)用SqlParser解析SQL語句得到Statement對象,并將Statement封裝成一個QueryStarter對象放入線程池中等待執(zhí)行。

SQL編譯過程

sql編譯過程

邏輯執(zhí)行計劃

邏輯執(zhí)行計劃

虛線就是Presto對邏輯執(zhí)行計劃的切分點

邏輯計劃Plan生成的SubPlan分為四個部分,每一個SubPlan都會提交到一個或者多個Worker節(jié)點上執(zhí)行

查詢執(zhí)行流程

查詢執(zhí)行流程
  • 1.Cli通過HTTP協(xié)議提交SQL查詢之后,查詢請求封裝成一個SqlQueryExecution對象交給Coordinator的SqlQueryManager#queryExecutor線程池去執(zhí)行

  • 2.每個SqlQueryExecution線程(圖中Q-X線程)啟動后對查詢請求的SQL進行語法解析和優(yōu)化并最終生成多個Stage的SqlStageExecution任務,每個SqlStageExecution任務仍然交給同樣的線程池去執(zhí)行

  • 3.每個SqlStageExecution線程(圖中S-X線程)啟動后每個Stage的任務按PlanDistribution屬性構(gòu)造一個或者多個RemoteTask通過HTTP協(xié)議分配給遠端的Worker節(jié)點執(zhí)行

  • 4.Worker節(jié)點接收到RemoteTask請求之后,啟動一個SqlTaskExecution線程(圖中T-X線程)將這個任務的每個Split包裝成一個PrioritizedSplitRunner任務(圖中SR-X)交給Worker節(jié)點的TaskExecutor#executor線程池去執(zhí)行

物理執(zhí)行計劃

物理執(zhí)行計劃

SubPlan的幾個屬性

planDistribution 分發(fā)方式

3種不同的PlanDistribution方式:
Source表示這個SubPlan是數(shù)據(jù)源,Source類型的任務會按照數(shù)據(jù)源大小確定分配多少個節(jié)點進行執(zhí)行;
Fixed表示這個SubPlan會分配固定的節(jié)點數(shù)進行執(zhí)行(Config配置中的query.initial-hash-partitions參數(shù)配置,默認是8);
None表示這個SubPlan只分配到一個節(jié)點進行執(zhí)行。

在下面的執(zhí)行計劃中,SubPlan1和SubPlan0 PlanDistribution=Source,這兩個SubPlan都是提供數(shù)據(jù)源的節(jié)點,SubPlan1所有節(jié)點的讀取數(shù)據(jù)都會發(fā)向SubPlan0的每一個節(jié)點;SubPlan2分配8個節(jié)點執(zhí)行最終的聚合操作;SubPlan3只負責輸出最后計算完成的數(shù)據(jù)。
outputPartitioning

OutputPartitioning屬性只有兩個值HASHNONE,

表示這個SubPlan的輸出是否按照partitionBy的key值對數(shù)據(jù)進行Shuffle。在下面的執(zhí)行計劃中只有SubPlan0的OutputPartitioning=HASH,所以SubPlan2接收到的數(shù)據(jù)是按照rank字段Partition后的數(shù)據(jù)

partitionBy

低延時查詢核心技術(shù)

完全基于內(nèi)存的并行計算

上述查詢執(zhí)行流程,均放在內(nèi)存線程中執(zhí)行

內(nèi)存中的數(shù)據(jù)模型

數(shù)據(jù)模型

Presto中處理的最小數(shù)據(jù)單元是一個Page對象,Page對象的數(shù)據(jù)結(jié)構(gòu)如下圖所示。
一個Page對象包含多個Block對象,每個Block對象是一個字節(jié)數(shù)組,存儲一個字段的若干行。多個Block橫切的一行是真實的一行數(shù)據(jù)。一個Page最大1MB,最多16*1024行數(shù)據(jù)。

流水線計算

流水線模型

流水線模型

左側(cè)是任務的執(zhí)行流程圖

Worker節(jié)點將最細粒度的任務封裝成一個PrioritizedSplitRunner對象,放入pending split優(yōu)先級隊列中。每個

Worker節(jié)點啟動一定數(shù)目的線程進行計算,線程數(shù)task.shard.max-threads=availableProcessors() * 4,在config中配置。

每個空閑的線程從隊列中取出一個PrioritizedSplitRunner對象執(zhí)行,如果執(zhí)行完成一個周期,超過最大執(zhí)行時間1秒鐘,判斷任務是否執(zhí)行完成,如果完成,從allSplits隊列中刪除,如果沒有,則放回pendingSplits隊列中。

每個任務的執(zhí)行流程如下圖右側(cè),依次遍歷所有Operator,嘗試從上一個Operator取一個Page對象,如果取得的Page不為空,交給下一個Operator執(zhí)行。

本地化計算

Presto在選擇Source任務計算節(jié)點的時候,對于每一個Split,按下面的策略選擇一些minCandidates

優(yōu)先選擇與Split同一個Host的Worker節(jié)點
如果節(jié)點不夠優(yōu)先選擇與Split同一個Rack的Worker節(jié)點
如果節(jié)點還不夠隨機選擇其他Rack的節(jié)點
對于所有Candidate節(jié)點,選擇assignedSplits最少的節(jié)點。

動態(tài)編譯執(zhí)行計劃

小心使用內(nèi)存和數(shù)據(jù)結(jié)構(gòu)

類BlinkDB的近似查詢

引入了一些近似查詢函數(shù)approx_avg、approx_distinct、approx_percentile

GC控制

參考鏈接
更多文章參見 微信號: life_361

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容