在 YARN 上配置 Spark

哈布尔,你好! 昨天 专门讨论 Apache Spark 的聚会来自 Rambler&Co 的人员,参与者提出了很多与配置此工具相关的问题。 我们决定追随他的脚步并分享我们的经验。 这个话题并不容易——所以我们邀请您在评论中分享您的经验,也许我们也理解和使用了一些错误的地方。

简单介绍一下我们如何使用 Spark。 我们有一个为期三个月的计划 “大数据专家”,在整个第二个模块中,我们的参与者都在使用该工具。 因此,作为组织者,我们的任务是准备集群以供在这种情况下使用。

我们使用的特殊性在于,同时在 Spark 上工作的人数可以等于整个小组。 例如,在研讨会上,每个人同时尝试某件事并跟着老师重复。 这并不是很多——有时最多 40 人。 世界上可能没有多少公司面临这样的用例。

接下来,我将告诉您我们如何以及为什么选择某些配置参数。

让我们从头开始吧。 Spark 有 3 个选项可以在集群上运行:独立、使用 Mesos 和使用 YARN。 我们决定选择第三个选项,因为它对我们来说很有意义。 我们已经有一个hadoop集群了。 我们的参与者已经非常熟悉它的架构。 让我们使用纱线。

spark.master=yarn

进一步更有趣。 这 3 个部署选项中的每一个都有 2 个部署选项:客户端和集群。 基于 文件资料 以及互联网上的各种链接,我们可以得出结论,客户端适合交互式工作——例如通过jupyter笔记本,而集群更适合生产解决方案。 就我们而言,我们对交互式工作感兴趣,因此:

spark.deploy-mode=client

一般来说,从现在开始,Spark 将以某种方式在 YARN 上工作,但这对我们来说还不够。 由于我们有一个关于大数据的项目,有时参与者没有在均匀分配资源的框架内获得足够的信息。 然后我们发现了一个有趣的事情——动态资源分配。 简而言之,要点是:如果您有一项艰巨的任务,并且集群空闲(例如,早上),那么使用 Spark 这个选项可以为您提供额外的资源。 必要性是根据一个狡猾的公式计算出来的。 我们不会详细介绍 - 它运作良好。

spark.dynamicAllocation.enabled=true

我们设置了这个参数,启动时Spark就崩溃了,没有启动。 没错,因为我必须读它 文件 更仔细地。 它指出,为了让一切正常,您还需要启用一个附加参数。

spark.shuffle.service.enabled=true

为什么需要它? 当我们的工作不再需要这么多资源时,Spark 应该将它们归还给公共池。 几乎所有 MapReduce 任务中最耗时的阶段是 Shuffle 阶段。 该参数允许您保存此阶段生成的数据并相应地释放执行器。 而executor就是在worker上计算一切的进程。 它具有一定数量的处理器核心和一定数量的内存。

已添加此参数。 一切似乎都很顺利。 值得注意的是,参与者实际上在需要时获得了更多资源。 但另一个问题出现了——在某个时候其他参与者醒来也想使用 Spark,但那里一切都很忙,他们不高兴。 他们是可以理解的。 我们开始查看文档。 事实证明,还有许多其他参数可以用来影响该过程。 例如,如果执行器处于待机模式,那么什么时间后可以从中取出资源?

spark.dynamicAllocation.executorIdleTimeout=120s

在我们的例子中,如果你的执行者在两分钟内没有做任何事情,那么请将它们返回到公共池中。 但这个参数并不总是足够的。 很明显,这个人已经很长时间没有做任何事情了,资源也没有被释放。 原来,还有一个特殊的参数——在什么时间之后选择包含缓存数据的执行器。 默认情况下,该参数为无穷大! 我们纠正了它。

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

也就是说,如果你的执行者在 5 分钟内没有做任何事情,就把它们交给公共池。 在这种模式下,大量用户的资源释放和发放速度变得不俗。 不满情绪有所减少。 但我们决定更进一步,限制每个应用程序的最大执行者数量 - 本质上是每个程序参与者。

spark.dynamicAllocation.maxExecutors=19

当然,现在另一边也有人不满意——“集群闲置了,我只有19个执行者”,但你能做什么呢?我们需要某种正确的平衡。 你不可能让每个人都开心。

还有一个与我们案例的具体情况相关的小故事。 不知何故,有几个人上实践课迟到了,而且由于某种原因 Spark 没有为他们开始。 我们查看了免费资源的数量 - 似乎就在那里。 Spark 应该启动。 幸运的是,那时文档已经添加到子皮层的某个地方,并且我们记得启动时,Spark 会寻找要启动的端口。 如果该范围内的第一个端口繁忙,它将按顺序移动到下一个端口。 如果它是免费的,它就会捕获。 并且有一个参数指示最大尝试次数。 默认是16人,这个数字比我们班上课的人数要少。 于是,尝试了16次后,Spark放弃了,说我无法启动。 我们已经更正了这个参数。

spark.port.maxRetries=50

接下来我会告诉你一些与我们案例的具体情况不太相关的设置。

为了更快地启动 Spark,建议将 SPARK_HOME 主目录中的 jars 文件夹存档并将其放在 HDFS 上。 这样他就不会浪费时间让工人装载这些jarniks。

spark.yarn.archive=hdfs:///tmp/spark-archive.zip

还建议使用 kryo 作为序列化器以实现更快的操作。 它比默认的更优化。

spark.serializer=org.apache.spark.serializer.KryoSerializer

Spark 还有一个长期存在的问题,就是经常从内存中崩溃。 这种情况通常发生在工作人员计算完所有内容并将结果发送给司机的时刻。 我们自己把这个参数调大了。 默认是1GB,我们设为3。

spark.driver.maxResultSize=3072

最后,作为甜点。 如何在 HortonWorks 发行版 - HDP 2.1 上将 Spark 更新到版本 2.5.3.0。 这个版本的 HDP 包含预装的 2.0 版本,但我们曾经自己决定 Spark 正在非常积极地开发,每个新版本都会修复一些错误并提供额外的功能,包括针对 python API 的功能,所以我们决定,需要什么完成是更新。

从官方网站下载了Hadoop 2.7的版本。 解压并放入HDP文件夹中。 我们根据需要安装了符号链接。 我们启动它 - 它没有启动。 写了一个很奇怪的错误。

java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig

经过谷歌,我们发现Spark决定不再等到Hadoop诞生,而决定使用新版本的球衣。 他们自己在 JIRA 中就这个话题互相争论。 解决办法是下载 球衣版本1.17.1。 将其放入 SPARK_HOME 的 jars 文件夹中,再次压缩并上传到 HDFS。

我们解决了这个错误,但又出现了一个新的、相当精简的错误。

org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master

同时,我们尝试运行2.0版本——一切正常。 尝试猜测发生了什么事。 我们查看了该应用程序的日志并看到了类似以下内容:

/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jar

一般来说,由于某种原因 hdp.version 没有解析。 经过谷歌搜索,我们找到了解决方案。 您需要转到 Ambari 中的 YARN 设置并将参数添加到自定义纱线站点:

hdp.version=2.5.3.0-37

这个魔法起了作用,Spark 起飞了。 我们测试了几台 jupyter 笔记本电脑。 一切正常。 我们已经准备好周六(明天)的第一节 Spark 课程了!

UPD。 上课的时候,又发现了一个问题。 在某个时候,YARN 停止为 Spark 提供容器。 在 YARN 中,需要更正参数,默认情况下为 0.2:

yarn.scheduler.capacity.maximum-am-resource-percent=0.8

即只有20%的资源参与了资源的分配。 更改参数后,我们重新加载 YARN。 问题已解决,其余参与者也能够运行 Spark 上下文。

来源: habr.com

添加评论