部署 Presto

安装 Presto

下载 Presto 服务器压缩包,presto-server-0.289.tar.gz,并解压它。该压缩包将包含一个顶级的目录,presto-server-0.289,我们将称之为安装目录。

Presto 需要一个用于存储日志等的数据目录。我们建议在安装目录之外创建一个数据目录,这样可以方便地在升级 Presto 时保留它。

配置 Presto

在安装目录中创建一个名为etc的目录。它将包含以下配置

  • 节点属性:每个节点特有的环境配置

  • JVM 配置:Java 虚拟机的命令行选项

  • 配置属性:Presto 服务器的配置。有关可用的配置属性,请参阅属性参考

  • 目录属性:用于连接器(数据源)的配置。连接器的可用目录配置属性在相应的连接器文档中描述。

节点属性

节点属性文件 etc/node.properties 包含特定于每个节点的配置。节点是指机器上安装的单个 Presto 实例。此文件通常在首次安装 Presto 时由部署系统创建。以下是一个最小的 etc/node.properties

node.environment=production
node.id=ffffffff-ffff-ffff-ffff-ffffffffffff
node.data-dir=/var/presto/data

上面的属性将在下面描述

  • node.environment: 环境名称。集群中的所有 Presto 节点必须具有相同的环境名称。

  • node.id: 此 Presto 安装的唯一标识符。这必须是每个节点的唯一标识符。此标识符应在 Presto 重启或升级后保持一致。如果在单个机器上运行多个 Presto 安装(即同一机器上的多个节点),则每个安装必须具有唯一的标识符。

  • node.data-dir: 数据目录的位置(文件系统路径)。Presto 将在这里存储日志和其他数据。

JVM 配置

JVM 配置文件 etc/jvm.config 包含用于启动 Java 虚拟机的命令行选项列表。该文件的格式是选项列表,每行一个选项。这些选项不会被 shell 解释,因此包含空格或其他特殊字符的选项不应该用引号括起来。

以下内容为创建 etc/jvm.config 提供了一个良好的起点

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

由于 OutOfMemoryError 通常会使 JVM 处于不一致状态,因此当发生这种情况时,我们会写入一个堆转储(用于调试)并强制终止进程。

配置属性

配置文件 etc/config.properties 包含 Presto 服务器的配置。每个 Presto 服务器都可以同时充当协调器和工作器,但将单个机器专用于执行协调工作可以为更大的集群提供最佳性能。

以下是协调器的最小配置

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

这是一个工作器的最小配置

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

或者,如果您正在设置一台机器进行测试,该机器将同时充当协调器和工作器,请使用以下配置

coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
query.max-memory=5GB
query.max-memory-per-node=1GB
discovery-server.enabled=true
discovery.uri=http://example.net:8080

如果单个协调器不足,请使用分散式协调器设置,该设置使用以下最小配置支持多个协调器

  • 资源 管理器

集群至少需要一个资源管理器,并且可以向集群添加更多资源管理器,每个资源管理器都充当主节点。

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://example.net:8080 (Point to resource manager host/vip)
thrift.server.ssl.enabled=true
  • 协调器

集群可以包含一组协调器。每个协调器将在集群中运行查询子集。

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://example.net:8080 (Point to resource manager host/vip)
resource-manager-enabled=true
  • 工作器

集群可以包含一组工作器。它们将其心跳发送到资源管理器。

coordinator=false
http-server.http.port=8080
query.max-memory=50GB
query.max-memory-per-node=1GB
discovery.uri=http://example.net:8080 (Point to resource manager host/vip)
resource-manager-enabled=true

这些属性需要一些解释

  • resource manager: 从协调器和工作器聚合数据,并构建集群的全局视图。有关更多详细信息,请阅读概念

  • coordinator: 允许此 Presto 实例充当协调器(接收来自客户端的查询并管理查询执行)。

  • node-scheduler.include-coordinator: 允许在协调器上调度工作。对于更大的集群,在协调器上处理工作可能会影响查询性能,因为该机器的资源不可用于调度、管理和监视查询执行的关键任务。

  • http-server.http.port: 指定 HTTP 服务器的端口。Presto 使用 HTTP 进行所有通信,包括内部和外部通信。

  • query.max-memory: 查询可能使用的最大分布式内存量。

  • query.max-memory-per-node: 查询在任何一台机器上可能使用的最大用户内存量。

  • discovery-server.enabled: Presto 使用 Discovery 服务来查找集群中的所有节点。每个 Presto 实例将在启动时向 Discovery 服务注册自己。为了简化部署并避免运行额外的服务,Presto 协调器可以运行 Discovery 服务的嵌入式版本。它与 Presto 共享 HTTP 服务器,因此使用相同的端口。

  • discovery.uri: Discovery 服务的 URI。因为我们在 Presto 协调器中启用了 Discovery 的嵌入式版本,所以它应该是 Presto 协调器的 URI。将 example.net:8080 替换为与 Presto 协调器的主机和端口匹配的值。此 URI 必须不以斜杠结尾。

以下标志可以帮助您调整分散式协调器集群的资源组,使其达到所需的稳定性

  • concurrency-threshold-to-enable-resource-group-refresh (default: 1.0)

    配置协调器在允许在任何给定的资源组上运行更多查询之前等待下一个资源组更新,前提是正在运行的查询已达到配置的限制。

    默认值为 1.0。这意味着一旦任何资源组正在运行其允许的最大查询数,协调器就必须等待来自资源管理器的更新,然后才能允许在给定的资源组上运行新查询。要实现更强的稳定性,请将百分比降低到更低的值。

  • resource-group-runtimeinfo-refresh-interval (default: 100 ms)

    此配置有助于调整协调器从资源管理器定期轮询集群级资源组使用情况的间隔。

您可能还想设置以下属性

  • jmx.rmiregistry.port: 指定 JMX RMI 注册表的端口。JMX 客户端应该连接到此端口。

  • jmx.rmiserver.port: 指定 JMX RMI 服务器的端口。Presto 导出许多可通过 JMX 监视的有用指标。

另请参阅资源组

日志级别

可选的日志级别文件 etc/log.properties 允许为命名的日志记录器层次结构设置最低日志级别。每个日志记录器都有一个名称,通常是使用该日志记录器的类的完全限定名称。日志记录器根据名称中的点(类似于 Java 包)具有层次结构。例如,考虑以下日志级别文件

com.facebook.presto=INFO

这将 com.facebook.presto.servercom.facebook.presto.hive 的最低级别设置为 INFO。默认的最低级别是 INFO。(因此,上面的示例实际上没有任何改变)共有四个级别:DEBUGINFOWARNERROR

目录属性

Presto 通过连接器访问数据,这些连接器被挂载在目录中。连接器提供目录中的所有模式和表。例如,Hive 连接器将每个 Hive 数据库映射到一个模式,因此,如果 Hive 连接器被挂载为 hive 目录,并且 Hive 在数据库 web 中包含一个表 clicks,则该表在 Presto 中被访问为 hive.web.clicks

目录通过在 etc/catalog 目录中创建目录属性文件来注册。例如,创建 etc/catalog/jmx.properties,其内容如下,将 jmx 连接器挂载为 jmx 目录

connector.name=jmx

有关配置连接器的更多信息,请参见 连接器

运行 Presto

安装目录包含 bin/launcher 中的启动器脚本。Presto 可以通过运行以下命令作为守护进程启动

bin/launcher start

或者,它可以在前台运行,日志和其他输出将写入 stdout/stderr(如果使用像 daemontools 这样的监督系统,则应捕获两个流)

bin/launcher run

使用 --help 运行启动器以查看支持的命令和命令行选项。特别是,--verbose 选项对于调试安装非常有用。

启动后,您可以在 var/log 中找到日志文件

  • launcher.log:此日志由启动器创建,并连接到服务器的 stdout 和 stderr 流。它将包含一些在服务器日志记录初始化期间发生的日志消息,以及 JVM 生成的任何错误或诊断信息。

  • server.log:这是 Presto 使用的主要日志文件。如果服务器在初始化期间失败,它通常会包含相关信息。它会自动轮换和压缩。

  • http-request.log:这是 HTTP 请求日志,其中包含服务器接收到的每个 HTTP 请求。它会自动轮换和压缩。

在笔记本电脑上查询 S3 的示例部署

本节演示如何在单台笔记本电脑上运行 Presto 连接到 Hive MetaStore 以查询 S3 存储桶中的数据。

配置 Hive MetaStore

下载并解压缩 Hive 的二进制 tarball。例如,下载并解压缩 apache-hive-<VERSION>-bin.tar.gz

您只需要启动 Hive MetaStore 来为 Presto 提供目录信息,例如表模式和分区位置。如果这是第一次启动 Hive MetaStore,请准备相应的配置文件和环境。另外,初始化一个新的 MetaStore

export HIVE_HOME=`pwd`
cp conf/hive-default.xml.template conf/hive-site.xml
mkdir -p hcatalog/var/log/
bin/schematool -dbType derby -initSchema

如果您想访问 AWS S3,请在 conf/hive-env.sh 中追加以下几行。Hive 需要相应的 jar 包来访问带有 s3a:// 地址的文件,以及 AWS 凭据来访问 S3 存储桶(即使它是公共的)。这些 jar 包可以在 Hadoop 发行版中找到(例如,在 ${HADOOP_HOME}/share/hadoop/tools/lib/ 下),或者从 Maven 中央仓库 下载。

export HIVE_AUX_JARS_PATH=/path/to/aws-java-sdk-core-<version>.jar:$/path/to/aws-java-sdk-s3-<version>.jar:/path/to/hadoop-aws-<version>.jar
export AWS_ACCESS_KEY_ID=<Your AWS Access Key>
export AWS_SECRET_ACCESS_KEY=<Your AWS Secret Key>

启动一个 Hive MetaStore,它将在后台运行并监听端口 9083(默认情况下)

hcatalog/sbin/hcat_server.sh start

输出类似于以下内容

Started metastore server init, testing if initialized correctly...
Metastore initialized successfully on port[9083].

要验证 MetaStore 是否正在运行,请检查 hcatalog/var/log/ 中的 Hive MetaStore 日志

配置 Presto

创建一个配置文件 etc/config.properties,基于 配置属性。例如,按照最小的配置在笔记本电脑上运行 Presto

coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
discovery-server.enabled=true
discovery.uri=https://127.0.0.1:8080

根据 JVM 配置 创建 etc/jvm.config,并根据 节点属性 创建 etc/node.properties

最后,在 etc/catalog/hive.properties 中配置 Presto Hive 连接器,指向刚刚启动的 Hive MetaStore 服务。如果 Presto 需要从 S3 读取输入文件,请在此处再次包含 AWS 凭据。

connector.name=hive-hadoop2
hive.metastore.uri=thrift://127.0.0.1:9083
hive.s3.aws-access-key=<Your AWS Access Key>
hive.s3.aws-secret-key=<Your AWS Secret Key>

运行 Presto 服务器

./bin/launcher start

使用 Docker 的示例部署

让我们看看如何为 Presto 构建一个 Docker 镜像。我们可以在下面看到如何轻松地让 Presto 运行起来。出于演示目的,此配置是一个单节点 Presto 安装,其中调度器将包含协调器作为工作节点。我们将配置一个目录,TPCH

对于 Dockerfile,我们下载 Presto,将一些配置文件从本地 etc 目录复制到镜像中,并指定一个入口点来运行服务器。

FROM openjdk:8-jre

# Presto version will be passed in at build time
ARG PRESTO_VERSION

# Set the URL to download
ARG PRESTO_BIN=https://repo1.maven.org/maven2/com/facebook/presto/presto-server/${PRESTO_VERSION}/presto-server-${PRESTO_VERSION}.tar.gz

# Update the base image OS and install wget and python
RUN apt-get update
RUN apt-get install -y wget python less

# Download Presto and unpack it to /opt/presto
RUN wget --quiet ${PRESTO_BIN}
RUN mkdir -p /opt
RUN tar -xf presto-server-${PRESTO_VERSION}.tar.gz -C /opt
RUN rm presto-server-${PRESTO_VERSION}.tar.gz
RUN ln -s /opt/presto-server-${PRESTO_VERSION} /opt/presto

# Copy configuration files on the host into the image
COPY etc /opt/presto/etc

# Download the Presto CLI and put it in the image
RUN wget --quiet https://repo1.maven.org/maven2/com/facebook/presto/presto-cli/${PRESTO_VERSION}/presto-cli-${PRESTO_VERSION}-executable.jar
RUN mv presto-cli-${PRESTO_VERSION}-executable.jar /usr/local/bin/presto
RUN chmod +x /usr/local/bin/presto

# Specify the entrypoint to start
ENTRYPOINT ./opt/presto/bin/launcher run

etc/ 文件夹中,有四个文件用于配置 Presto,以及一个目录在 etc/catalog/ 中。目录定义了连接器的配置,目录以文件名(减去 .properties 扩展名)命名。您可以在每个 Presto 安装中拥有多个目录,包括使用相同连接器的多个目录;它们只需要不同的文件名。这些文件是

etc/
├── catalog
│   └── tpch.properties  # Configures the TPCH connector to generate data
├── config.properties    # Presto instance configuration properties
├── jvm.config           # JVM configuration for the process
├── log.properties       # Logging configuration
└── node.properties      # Node-specific configuration properties

直接位于 etc 下的四个文件在上面有说明(使用单节点协调器配置用于 config.properties)。名为 etc/catalog/tpch.properties 的文件用于定义 tpch 目录。每个连接器都有自己的一组特定于连接器的配置属性。您可以在连接器文档中找到连接器的配置属性。TPCH 连接器没有特殊配置,因此我们只为目录指定连接器名称,也是 tpch

etc/catalog/tpch.properties

connector.name=tpch

现在我们准备构建 Docker 容器,指定版本,然后启动 Presto。Presto 的最新版本目前是 0.289。

docker build --build-arg PRESTO_VERSION=<see releases for latest version> . -t prestodb:latest
docker run --name presto prestodb:latest

您将看到一系列 Presto 启动时的日志,最后以 SERVER STARTED 结束,表示它已准备好接收查询。我们将使用 Presto CLI 连接到我们放在镜像中的 Presto,使用一个单独的终端窗口。

docker exec -it presto presto

现在我们可以对 tpch 目录执行查询。

presto> SELECT
     ->   l.returnflag,
     ->   l.linestatus,
     ->   sum(l.quantity)                                       AS sum_qty,
     ->   sum(l.extendedprice)                                  AS sum_base_price,
     ->   sum(l.extendedprice * (1 - l.discount))               AS sum_disc_price,
     ->   sum(l.extendedprice * (1 - l.discount) * (1 + l.tax)) AS sum_charge,
     ->   avg(l.quantity)                                       AS avg_qty,
     ->   avg(l.extendedprice)                                  AS avg_price,
     ->   avg(l.discount)                                       AS avg_disc,
     ->   count(*)                                              AS count_order
     -> FROM
     ->   tpch.sf1.lineitem AS l
     -> WHERE
     ->   l.shipdate <= DATE '1998-12-01' - INTERVAL '90' DAY
     -> GROUP BY
     ->   l.returnflag,
     ->   l.linestatus
     -> ORDER BY
     ->   l.returnflag,
     ->   l.linestatus;
 returnflag | linestatus |   sum_qty   |    sum_base_price     |    sum_disc_price     |      sum_charge       |      avg_qty       |     avg_price     |       avg_disc       | count_order
------------+------------+-------------+-----------------------+-----------------------+-----------------------+--------------------+-------------------+----------------------+-------------
 A          | F          | 3.7734107E7 |  5.658655440072982E10 | 5.3758257134869644E10 |  5.590906522282741E10 | 25.522005853257337 | 38273.12973462155 |  0.04998529583846928 |     1478493
 N          | F          |    991417.0 |  1.4875047103800006E9 |  1.4130821680540998E9 |   1.469649223194377E9 | 25.516471920522985 | 38284.46776084832 |  0.05009342667421586 |       38854
 N          | O          |  7.447604E7 | 1.1170172969773982E11 | 1.0611823030760503E11 | 1.1036704387249734E11 |  25.50222676958499 | 38249.11798890821 |   0.0499965860537345 |     2920374
 R          | F          | 3.7719753E7 |   5.65680413808999E10 |  5.374129268460365E10 |  5.588961911983193E10 |  25.50579361269077 | 38250.85462609959 | 0.050009405830198916 |     1478870
(4 rows)

Query 20200625_171123_00000_xqmp4, FINISHED, 1 node
Splits: 56 total, 56 done (100.00%)
0:05 [6M rows, 0B] [1.1M rows/s, 0B/s]