秒級查詢之開源分散式SQL查詢引擎Presto實操-上

itxiaoshen 發表於 2022-12-08
SQL

@

概述

定義

Presto 官網地址 https://prestodb.io/

Presto 官網文件 https://prestodb.io/docs/current/

Presto GitHub原始碼地址 https://github.com/prestodb/presto

Presto是一個開源的分散式SQL查詢引擎,特點是快速、可靠、高效,也可便捷快速的整合到湖倉一體架構中。最新版本為0.278

Presto是 Facebook 開源的 MPP (Massive Parallel Processing) SQL 引擎,資料量支援GB到PB位元組;常用於大資料互動式查詢場景,其支援並行查詢分佈在一個或多個異構資料來源上的大型資料集,可實現亞秒級響應效能。Presto旨在處理資料倉儲和資料分析,聚合大量資料並生成報告。也即是Presto適合於線上分析處理(OLAP)。雖然其查詢效能稍遜於Impala,但是Presto功能則更加強大,支援豐富資料來源包含Hive、圖資料庫、傳統關係型資料庫、Redis等。

注意:Presto不是一個通用的關聯式資料庫;它不是MySQL、PostgreSQL或Oracle等資料庫的替代品,其主要為處理聯機事務處理(OLTP)而設計的。

概念

  • 伺服器型別:resource manager(資源管理器), coordinators(協調器)、 workers(工作者)
    • Resource Manager:聚合來自所有coordinators和workers的資料的伺服器,並構建叢集的全域性檢視。立即安裝與分解coordinators必須需要資源管理器。叢集支援多個資源管理器,每個資源管理器充當一個主資源管理器。coordinators和workers使用thrift API與資源管理器通訊。
    • Coordinators:負責解析語句、規劃查詢和管理Presto工作節點的伺服器。它是Presto安裝的“大腦”,也是客戶端連線到的節點,以提交語句以執行。每個Presto安裝必須有一個Presto coordinators和一個或多個worker工人。跟蹤每個worker上的活動,並協調查詢的執行。coordinators建立一個包含一系列階段的查詢邏輯模型,然後將其轉換為在Presto worker叢集上執行的一系列連線任務。coordinators使用REST API與worker和客戶機通訊。如果是僅用於開發或測試的目的,可以配置一個Presto例項來執行這兩個角色。
    • Workers:是Presto安裝中的伺服器,負責執行任務和處理資料。workers節點從聯結器獲取資料,並彼此交換中間資料。coordinators負責從worker獲取結果,並將最終結果返回給客戶機。當一個Presto工作程式啟動時,它會在coordinators中將自己釋出給發現伺服器,這使得它可以供Presto協調器執行任務。workers使用REST API與其他workers和Presto coordinators進行通訊。
  • 資料來源
    • Connector :聯結器使Presto適應資料來源,如Hive或關聯式資料庫,是Presto SPI的實現,使用標準API與資源互動。Presto內建聯結器有用於JMX的聯結器、提供對內建系統表訪問的系統聯結器、Hive聯結器和用於提供TPC-H基準測試資料的TPCH聯結器。也支援第三方開發聯結器,以便Presto可以訪問各種資料來源中的資料。
    • Catalog:包含模式並透過聯結器引用資料來源。例如配置一個JMX目錄,以透過JMX聯結器提供對JMX資訊的訪問。catalog定義在儲存在Presto配置目錄中的屬性檔案中。
    • Schema:是一種組織表的方法。和schema一起定義了一組可以查詢的表。使用Presto訪問Hive或關聯式資料庫(如MySQL)時,模式在目標資料庫中轉換為相同的概念。其他型別的聯結器可能選擇以對底層資料來源有意義的方式將表組織到模式中。
    • Table:表是一組無序的行,它們被組織成具有型別的命名列。這與任何關聯式資料庫中的情況相同。從源資料到表的對映由聯結器定義。
  • 查詢執行模型:Presto執行SQL語句,並將這些語句轉換為coordinators和workers的分散式叢集執行的查詢。
    • Statement:Presto執行ansi相容的SQL語句,該標準由子句、表示式和謂片語成。
    • Query:解析一條語句時,它將其轉換為一個查詢,並建立一個分散式查詢計劃,然後將其實現為在Presto worker上執行的一系列相互連線的階段。語句和查詢之間的區別很簡單。一條語句可以被認為是傳遞給Presto的SQL文字,而查詢則是指為執行該語句而例項化的配置和元件。查詢包括階段、任務、分段、聯結器以及協同工作以產生結果的其他元件和資料來源。
    • Stage:Presto執行查詢時,透過將執行分解為階段層次結構來執行。例如需要聚合Hive中儲存的十億行的資料,它會建立一個根階段來聚合其他幾個階段的輸出,所有這些階段都是為了實現分散式查詢計劃的不同部分而設計的。組成查詢的階段層次結構類似於樹。每個查詢都有一個根階段,負責聚合來自其他階段的輸出。階段是協調器用來建模分散式查詢計劃,但是階段本身並不在Presto worker上執行。
    • Task:stage對分散式查詢計劃的特定部分建模,但stage本身並不在Presto worker上執行。任務是Presto體系結構中的工作項,因為分散式查詢計劃被分解為一系列階段,然後轉換為任務,然後這些任務作用於或處理分割。Presto任務有輸入和輸出,就像一個階段可以由一系列任務並行執行一樣,一個任務也可以與一系列驅動程式並行執行。
    • Split:任務在分片上操作,分片是更大資料集的部分。分散式查詢計劃的最低階別的階段透過聯結器的分割檢索資料,分散式查詢計劃較高階別的中間階段從其他階段檢索資料。當Presto排程查詢時,協調器將查詢一個聯結器,以獲得一個表中可用的所有分割的列表。協調器跟蹤哪些機器正在執行哪些任務,以及哪些任務正在處理哪些分割。
    • Driver:任務包含一個或多個並行驅動程式。驅動程式作用於資料並結合運算子以產生輸出,然後由一個任務聚合,然後交付給另一個階段的另一個任務。驅動程式是運算子例項的序列,它是Presto體系結構中並行度的最低階別。驅動程式有一個輸入和一個輸出。
    • Operator:運算子消費、轉換和生成資料。例如,表掃描從聯結器獲取資料並生成可被其他運算子使用的資料,篩選運算子使用資料並透過對輸入資料應用謂詞來生成子集。
    • Exchange:交換在Presto節點之間為查詢的不同階段傳輸資料。任務將資料生成到輸出緩衝區,並使用交換客戶機使用來自其他任務的資料。

架構

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-puiIUWlb-1670510239411)(image-20221208091733068.png)]

  • 先從Presto CLI提交到Coordinator,也即是由客戶端來提交查詢請求。
  • Coordinator透過SQL解析生成查詢計劃並把任務分發給一個或多個worker去執行。
  • Worker負責執行具體任務和處理資料。
  • Catelog表示資料來源,一個catelog包括connector和schema、table。
    • Connector是連線介面卡,用於Presto和資料來源(如hive,redis)的連線,類似於JDBC。也可以自定義程式設計實現聯結器
    • Schema類似於mysql中資料庫,table類似於mysql中表。
  • Coordinator是負責從worker獲取結果並返回最終結果給client。

Presto查詢請求是分Stage階段執行,示例如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-WeSqiwpp-1670510239413)(image-20221208111107526.png)]

優缺點

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-VCnUmXmQ-1670510239414)(image-20221208111752965.png)]

  • 優點
    • Presto基於記憶體運算,減少了磁碟IO,因此計算更快。
    • Presto 支援多資料來源,且能夠同時連線多個資料來源進行跨資料來源連表查詢;比如可以從Hive查詢大量APP網站訪問記錄然後從Mysql中關聯匹配出對應的裝置資訊。
    • 部署比Hive更簡單(Hive是依賴於HDFS)。
  • 缺點
    • Presto 能夠處理PB級別的海量資料分析,但Presto並不是把PB級資料都放在記憶體中計算的。而是根據場景,如Count、AVG等聚合hanshu ,是邊讀資料邊計算,再清記憶體然後重複讀資料和計算,這種耗的記憶體並不高。但是連表查就可能出現大量的臨時資料,因此速度會變慢。

聯結器

支援聯結器很多,從關聯式資料庫、NoSQL資料庫、Hive等,還包括對支援目前主流三大資料湖技術Delta Lake、Hudi、Iceberg的聯結器

  • Accumulo Connector
  • BigQuery Connector
  • Black Hole Connector
  • Cassandra Connector
  • ClickHouse connector
  • Delta Lake Connector
  • Druid Connector
  • Elasticsearch Connector
  • Hive Connector
  • Hive Security Configuration
  • Hudi connector
  • Iceberg Connector
  • JMX Connector
  • Kafka Connector
  • Kafka Connector Tutorial
  • Kudu Connector
  • Lark Sheets connector
  • Local File Connector
  • Memory Connector
  • MongoDB Connector
  • MySQL Connector
  • Oracle Connector
  • Apache Pinot Connector
  • PostgreSQL Connector
  • Prometheus Connector
  • Redis Connector
  • Redshift Connector
  • SQL Server Connector
  • System Connector
  • Thrift Connector
  • TPCDS Connector
  • TPCH Connector

部署

叢集安裝

# 建立presto的資料目錄,
mkdir presto-data
# 下載最新版的presto二進位制包
wget https://repo1.maven.org/maven2/com/facebook/presto/presto-server/0.278/presto-server-0.278.tar.gz
# 解壓
tar -xvf presto-server-0.278.tar.gz
# 進入根目錄
cd presto-server-0.278
# 建立配置目錄
mkdir etc
# 建立catalog
mkdir etc/catalog

新增節點配置檔案,vim etc/node.properties

# 環境的名稱,叢集中的所有Presto節點必須具有相同的環境名稱。
node.environment=production
# 節點的id,此Presto安裝的唯一識別符號。這對於每個節點都必須是唯一的。這個識別符號應該在重啟或升級Presto時保持一致。如果在一臺機器上執行多個Presto安裝(即同一臺機器上的多個節點),每個安裝必須有唯一的識別符號。
node.id=ffffffff-ffff-ffff-ffff-fffffffffff1
# 節點資料目錄的位置(檔案系統路徑),Presto將在這裡儲存日誌和其他資料。
node.data-dir=/home/commons/presto-data

新增JVM引數配置,vim etc/jvm.config

-server
-Xmx16G
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+UseGCOverheadLimit
-XX:+ExplicitGCInvokesConcurrent
-XX:+HeapDumpOnOutOfMemoryError
-XX:+ExitOnOutOfMemoryError

如果規劃為coordinator節點,新增的主配置檔案,vim etc/config.properties

coordinator=true
node-scheduler.include-coordinator=false
http-server.http.port=8084
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery-server.enabled=true
discovery.uri=http://hadoop1:8084

如果規劃為worker節點,新增的主配置檔案,vim etc/config.properties

coordinator=false
http-server.http.port=8084
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery.uri=http://hadoop1:8084

配置日誌級別,vim etc/log.properties

# 日誌級別有四種,DEBUG, INFO, WARN and ERROR
com.facebook.presto=INFO

在etc/catalog/目錄配置Presto Hive聯結器,vim etc/catalog/hive.properties

connector.name=hive-hadoop2
hive.metastore.uri=thrift://hadoop2:9083
#如果hive metastore的引用檔案存放在一個存在聯邦的HDFS上,或者你是透過其他非標準的客戶端來訪問HDFS叢集的,請新增以下配置資訊來指向你的HDFS配置檔案:
hive.config.resources=/home/commons/hadoop/etc/hadoop/core-site.xml,/home/commons/hadoop/etc/hadoop/hdfs-site.xml
# 將資料目錄和安裝目錄presto-server-0.278複製到其他節點,修改node.id每臺唯一,這裡以一個協調節點和3個worker節點為例
# 啟動每個節點,安裝目錄中包含bin/launcher中的啟動器指令碼,Presto可以作為一個守護程式啟動,執行命令如下
bin/launcher start
# 可以在前臺執行,日誌和其他輸出被寫入stdout/stderr
bin/launcher run

常用配置說明

  • coordinator:指定是否運維Presto例項作為一個coordinator(接收來自客戶端的查詢情切管理每個查詢的執行過程)。
  • node-scheduler.include-coordinator:是否允許在coordinator服務中進行排程工作。對於大型的叢集,在一個節點上的Presto server即作為coordinator又作為worke將會降低查詢效能。因為如果一個伺服器作為worker使用,那麼大部分的資源都不會被worker佔用,那麼就不會有足夠的資源進行關鍵任務排程、管理和監控查詢執行。
  • http-server.http.port:指定HTTP server的埠。Presto 使用 HTTP進行內部和外部的所有通訊。
  • task.max-memory=1GB:一個單獨的任務使用的最大記憶體 (一個查詢計劃的某個執行部分會在一個特定的節點上執行)。 這個配置引數限制的GROUP BY語句中的Group的數目、JOIN關聯中的右關聯表的大小、ORDER BY語句中的行數和一個視窗函式中處理的行數。 該引數應該根據併發查詢的數量和查詢的複雜度進行調整。如果該引數設定的太低,很多查詢將不能執行;但是如果設定的太高將會導致JVM把記憶體耗光。
  • discovery-server.enabled:Presto 透過Discovery 服務來找到叢集中所有的節點。為了能夠找到叢集中所有的節點,每一個Presto例項都會在啟動的時候將自己註冊到discovery服務。Presto為了簡化部署,並且也不想再增加一個新的服務程式,Presto coordinator 可以執行一個內嵌在coordinator 裡面的Discovery 服務。這個內嵌的Discovery 服務和Presto共享HTTP server並且使用同樣的埠。
  • discovery.uri:Discovery server的URI。由於啟用了Presto coordinator內嵌的Discovery 服務,因此這個uri就是Presto coordinator的uri。修改example.net:8080,根據你的實際環境設定該URI。注意:這個URI一定不能以“/“結尾。

資源管理安裝模式

如果規模大可以部署為資源管理器、協調器池、worker池的叢集模式。

  • 一個叢集至少需要1個資源管理器,可以向叢集中新增更多資源管理器,每個資源管理器都充當主資源管理器。資源管理器的配置節點,vim etc/config.properties
resource-manager=true
resource-manager-enabled=true
coordinator=false
node-scheduler.include-coordinator=false
http-server.http.port=8080
thrift.server.port=8081
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery-server.enabled=true
discovery.uri=http://hadoop1:8080
thrift.server.ssl.enabled=true
  • 叢集支援協調器池。每個協調器將執行叢集中的查詢子集。協調器的配置節點,vim etc/config.properties
coordinator=true
node-scheduler.include-coordinator=false
http-server.http.port=8080
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery.uri=http://hadoop1:8080
resource-manager-enabled=true
  • 叢集支援worker池,把自己的心跳發給資源管理器。worker的配置節點,vim etc/config.properties
coordinator=false
http-server.http.port=8080
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery.uri=http://hadoop1:8080
resource-manager-enabled=true

安裝命令列介面

# 下載最新版本0.278
wget https://repo1.maven.org/maven2/com/facebook/presto/presto-cli/0.278/presto-cli-0.278-executable.jar
# 賦可執行許可權
chmod a+x ./presto-cli-0.278-executable.jar
# 進入命令列介面
./presto-cli-0.278-executable.jar --server hadoop1:8084 --catalog hive --schema default
# 執行sql
presto:default> show schemas;
presto:default> use test;
presto:test> show tables;
presto:test> select * from emp_mid;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-XPSx33KD-1670510239416)(image-20221208181548599.png)]

基於Tableau Web 聯結器

Tableau的Presto web聯結器允許使用者從Tableau對Presto執行查詢。它實現了Tableau web聯結器API中的函式。

直接訪問http://hadoop1:8084/tableau/presto-connector.html

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Y4ZdXkuq-1670510239417)(image-20221208182302170.png)]

使用最佳化

資料儲存

  • 合理設定分割槽:與Hive類似,Presto會根據元資訊讀取分割槽資料,合理的分割槽能減少Presto資料讀取量,提升查詢效能。
  • 使用列式儲存:Presto對ORC檔案讀取做了特定最佳化,因此在Hive中建立Presto使用的表時,建議採用ORC格式儲存;相對於Parquet,Presto對ORC支援更好。
  • 使用壓縮:資料壓縮可以減少節點間資料傳輸對IO頻寬壓力,對於即席查詢需要快速解壓,建議採用Snappy壓縮。
  • 預先排序:對於已經排序的資料,在查詢的資料過濾階段,ORC格式支援跳過讀取不必要的資料,比如對於經常需要過濾的欄位可以預先排序。

查詢SQL最佳化

  • 只選擇使用必要的欄位:由於採用列式儲存,選擇需要的欄位可加快欄位的讀取、減少資料量。避免採用*讀取所有欄位。
  • 過濾條件必須加上分割槽欄位:對於有分割槽的表,where語句中優先使用分割槽欄位進行過濾。acct_day是分割槽欄位,visit_time是具體訪問時間。
  • Group By語句最佳化:合理安排Group by語句中欄位順序對效能有一定提升。將Group By語句中欄位按照每個欄位distinct資料多少進行降序排列。
  • Order by時使用Limit:Order by需要掃描資料到單個worker節點進行排序,導致單個worker需要大量記憶體。如果是查詢Top N或者Bottom N,使用limit可減少排序計算和記憶體壓力。
  • 使用近似聚合函式Presto有一些近似聚合函式,對於允許有少量誤差的查詢場景,使用這些函式對查詢效能有大幅提升。比如使用approx_distinct() 函式比Count(distinct x)有大概2.3%的誤差。SELECT approx_distinct(user_id) FROM access
  • 用regexp_like代替多個like語句:Presto查詢最佳化器沒有對多個like語句進行最佳化,使用regexp_like對效能有較大提升。
  • 使用Join語句時將大表放在左邊:Presto中join的預設演算法是broadcast join,即將join左邊的表分割到多個worker,然後將join右邊的表資料整個複製一份傳送到每個worker進行計算。如果右邊的表資料量太大,則可能會報記憶體溢位錯誤。
  • 使用Rank函式代替row_number函式來獲取TopN。

無縫替換Hive表

  • 建立對應的orc表
  • 先將資料灌入orc表,然後更換表名
  • 其中原表不要刪除,若線上執行一段時間後沒有出現問題,則可以刪除該源表。

建表格式的選擇

  • ORC和Parquet都支援列式儲存,但是ORC對Presto支援更好(Parquet對Impala支援更好)
  • 對於列式儲存而言,儲存檔案為二進位制的,對於經常增刪欄位的表,建議不要使用列式儲存(修改檔案後設資料代價大)。對比資料倉儲,dwd層建議不要使用ORC,而dm層則建議使用。

本人部落格網站IT小神 www.itxiaoshen.com