在 CDH 中调优 Apache Hive on Spark

Spark 上的 Hive 在提供相同功能的同时提供比 MapReduce 上的 Hive 更好的性能。在 Spark 上运行 Hive 不需要更改用户查询。具体来说,完全支持用户定义函数 (UDF),并且大多数与性能相关的配置都使用相同的语义。

本主题介绍如何在 Spark 上配置和调整 Hive 以获得最佳性能。本主题假设您的集群由 Cloudera Manager 管理,并且您使用 YARN 作为 Spark 集群管理器。

以下部分中描述的示例假设一个 40 主机 YARN 集群,每台主机有 32 个内核和 120 GB 内存。

Yarn 配置

YARN 属性yarn.nodemanager.resource.cpu-vcores和yarn.nodemanager.resource.memory-mb确定 Hive on Spark(和其他 YARN 应用程序)如何使用集群资源。这两个属性的值由主机的容量和在同一主机上共存的其他非 YARN 应用程序的数量决定。最常见的是,只有 YARN NodeManager 和 HDFS DataNode 服务在工作主机上运行。

核心配置

为每个服务分配 1 个核心,为操作系统使用额外的 2 个核心,为 YARN 保留 28 个核心。

配置内存

为这些服务和进程分配 20 GB 内存。为此,请设置yarn.nodemanager.resource.memory-mb=100 GB和yarn.nodemanager.resource.cpu-vcores=28.

有关调整 YARN 的更多信息,请参阅调整 YARN。

Spark 配置

将资源分配给 YARN 后,您可以定义 Spark 如何使用资源:执行程序和驱动程序内存、执行程序分配和并行性。

配置执行器内存

Spark 执行器配置在配置 YARN 应用程序上的 Spark 中进行了描述。

设置执行器内存大小时,请考虑以下因素:
  • 更多的执行器内存可以为更多查询启用映射连接优化,但可能会由于垃圾收集而导致开销增加。
  • 在某些情况下,HDFS 客户端不能很好地处理并发写入程序,因此如果执行程序具有太多核心,则可能会出现竞争情况。

为了尽量减少未使用的核心数量,Cloudera 建议设置spark.executor.cores4、5 或 6,具体取决于分配给 YARN 的核心数。

因为 28 核可以被 4 整除,所以设置spark.executor.cores至 4. 将其设置为 6 将使 4 个核心未使用;将其设置为 5 会使 3 个核心未使用。和 spark.executor.cores设置为 4,可以在主机上并发运行的最大执行程序数为 7 (28 / 4)。在这些执行程序之间分配总内存,每个执行程序大约有 14 GB (100 / 7)。

分配给执行程序的总内存包括spark.executor.memory和spark.yarn.executor.memoryOverhead. 默认为spark.yarn.executor.memoryOverhead是 executorMemory * 0.10,最小值为 384。此属性表示要为每个执行程序分配的堆外内存(单位 = MB)。堆外内存用于 VM 开销、实习字符串和其他开销,并随着执行程序大小的 5-10% 成比例地增加。

如果需要设置不同于默认值的值,以下示例显示如何在 Hive Session中动态设置属性:

set spark.executor.memory=12g;

set spark.yarn.executor.memoryOverhead=2g;

通过这些配置,每台主机一次最多可以运行 7 个执行程序。每个执行器最多可以运行 4 个任务(每个核心一个)。因此,每个任务平均有 3.5 GB (14 / 4) 内存。在 executor 中运行的所有任务共享相同的堆空间。

确保总和spark.yarn.executor.memoryOverhead和spark.executor.memory小于yarn.scheduler.maximum-allocation-mb.

配置驱动程序内存

您还必须配置 Spark 驱动程序内存:
  • spark.driver.memory— 当 Hive 在 Spark 上运行时,每个 Spark 驱动程序的 Java 堆内存的最大大小。
  • spark.yarn.driver.memoryOverhead— 每个驱动程序可以从 YARN 请求的额外堆外内存量。这与spark.driver.memory, 是 YARN 可用于为驱动程序进程创建 JVM 的总内存。
Spark 驱动程序内存不会直接影响性能,但它可以确保 Spark 作业在驱动程序处不受内存限制的情况下运行。使用以下公式调整分配给 Spark 驱动程序的内存总量,假设值为yarn.nodemanager.resource.memory-mb是:
  • 当X大于 50 GB时为12 GB
  • 当X介于 12 GB 和 50 GB 之间时为 4 GB
  • 当X介于 1GB 和 12 GB 之间时为 1 GB
  • 当X小于 1 GB时为256 MB

这些数字是总和spark.driver.memory和spark.yarn.driver.memoryOverhead. 开销应占总数的 10-15%。在这个例子中,yarn.nodemanager.resource.memory-mb=100 GB,因此 Spark 驱动程序的总内存可以设置为 12 GB。因此,内存设置是 spark.driver.memory=10.5gb和spark.yarn.driver.memoryOverhead=1.5gb.

选择Executors 的数量

一个集群的 executor 数量由每台主机上的 executor 数量和集群中 worker 主机的数量决定。如果您的集群中有 40 个工作程序主机,则 Hive 可用于在 Spark 作业上运行 Hive 的最大执行程序数为 160 (40 x 4)。最大值略小于此值,因为驱动程序使用一个内核和 12 GB 总驱动程序内存。这假定没有其他 YARN 应用程序正在运行。

Hive 性能与用于运行查询的执行程序的数量直接相关。但是,特征因查询而异。一般来说,性能与执行者的数量成正比。例如,使用四个执行器进行查询大约需要使用两个执行器的时间的一半。但是,在一定数量的 executor 上性能达到峰值,超过该数量并不会提高性能,并且可能会产生不利影响。

在大多数情况下,使用集群容量的一半(执行器数量的一半)可以提供良好的性能。为了获得最佳性能,最好使用所有可用的执行程序。例如,设置spark.executor.instances=160. 对于基准测试和性能测量,强烈建议这样做。

动态 Executors 分配

虽然设置spark.executor.instances到最大值通常可以最大限度地提高性能,不建议在多个用户运行 Hive 查询的生产环境中这样做。避免为用户会话分配固定数量的执行器,因为如果执行器空闲,其他用户查询将无法使用这些执行器。在生产环境中,计划执行器分配以允许更大的资源共享。

Spark 允许您根据工作负载动态扩展分配给 Spark 应用程序的集群资源集。要启用动态分配,请遵循动态分配中的过程。除某些情况外,Cloudera 强烈建议启用动态分配。

并行性

为了充分利用可用的执行程序,您必须同时(并行)运行足够的任务。在大多数情况下,Hive 会自动为您确定并行度,但您可能在调整并发方面有一些控制权。在输入端,map 任务的数量等于输入格式生成的 split 数量。对于 Spark 上的 Hive,输入格式为组合蜂巢输入格式,它可以根据需要对底层输入格式生成的拆分进行分组。您可以更好地控制阶段边界的并行性。调整 hive.exec.reducers.bytes.per.reducer控制每个 reducer 处理的数据量,Hive 根据可用的执行程序、执行程序内存设置、您为属性设置的值和其他因素确定最佳分区数。实验表明,Spark 对您指定的值的敏感性不如 MapReducehive.exec.reducers.bytes.per.reducer,只要生成足够的任务以使所有可用的执行程序保持忙碌。为了获得最佳性能,请为该属性选择一个值,以便 Hive 生成​​足够的任务来充分利用所有可用的执行程序。

有关调整 Spark 应用程序的更多信息,请参阅 调整 Apache Spark 应用程序。

Hive 配置

Spark 上的 Hive 共享大多数(如果不是全部)与 Hive 性能相关的配置。您可以像调整 MapReduce 一样调整这些参数。然而,hive.auto.convert.join.noconditionaltask.size,这是根据统计信息将 common join 转换为 map join 的阈值,可能会对性能产生重大影响。尽管此配置用于 MapReduce 上的 Hive 和 Spark 上的 Hive,但它们的解释不同。

数据的大小由两个统计数据描述:
  • totalSize — 磁盘上数据的近似大小
  • rawDataSize — 内存中数据的近似大小

MapReduce 上的 Hive 使用totalSize. 当两者都可用时,Hive on Spark 使用 rawDataSize. 由于压缩和序列化,两者之间的差异很大 totalSize 和 rawDataSize 可能发生在同一数据集上。对于 Hive on Spark,您可能需要为hive.auto.convert.join.noconditionaltask.size 将相同的连接转换为 map 连接。您可以增加此参数的值以使 map 连接转换更加积极。将 common join 转换为 map join 可以提高性能。或者,如果这个值设置得太高,来自小表的数据会占用过多的内存,并且任务可能会因为内存不足而失败。根据您的集群环境调整此值。

你可以控制是否 rawDataSize 应使用该属性收集统计信息hive.stats.collect.rawdatasize. Cloudera 建议将此设置为 true 的在 Hive 中(默认)。

Cloudera 还建议使用 HiveServer2 的 Cloudera Manager 高级配置片段设置两个额外的配置属性:

  • hive.stats.fetch.column.stats=true
  • hive.optimize.index.filter=true
通常建议使用以下属性进行 Hive 性能调整,尽管它们并非特定于 Hive on Spark:
hive.optimize.reducededuplication.min.reducer=4
hive.optimize.reducededuplication=true
hive.merge.mapfiles=true
hive.merge.mapredfiles=false
hive.merge.smallfiles.avgsize=16000000
hive.merge.size.per.task=256000000
hive.merge.sparkfiles=true
hive.auto.convert.join=true
hive.auto.convert.join.noconditionaltask=true
hive.auto.convert.join.noconditionaltask.size=20M(Spark可能需要增加,200M)
hive.optimize.bucketmapjoin.sortedmerge=false
hive.map.aggr.hash.percentmemory=0.5
hive.map.aggr=true
hive.optimize.sort.dynamic.partition=false
hive.stats.autogather=true
hive.stats.fetch.column.stats=true
hive.compute.query.using.stats=true
hive.limit.pushdown.memory.usage=0.4(MR 和 Spark)
hive.optimize.index.filter=true
hive.exec.reducers.bytes.per.reducer=67108864
hive.smbjoin.cache.rows=10000
hive.fetch.task.conversion=更多
hive.fetch.task.conversion.threshold=1073741824
hive.optimize.ppd=true

你可能感兴趣的:(大数据/架构,hive,hadoop,spark)