前言
资源是影响 Spark 利用执行效率的一个重要因素。Spark 利用中真正执行 task 的组件是 Executor,能够通过 spark.executor.instances 指定 Spark 利用的 Executor 的数量。在运行过程中,无论 Executor 上是否有 task 在执行,都会被始终占有直到此 Spark 利用完结。
上篇咱们从动静优化的角度讲述了 Spark 3.0 版本中的自适应查问个性,它次要是在一条 SQL 执行过程中一直优化执行逻辑,抉择更好的执行策略,从而达到晋升性能的目标。本篇咱们将从整个 Spark 集群资源的角度探讨一个常见痛点:资源有余。
在 Spark 集群中的一个常见场景是,随着业务的一直倒退,须要运行的 Spark 利用数和数据量越来越大,靠资源堆砌的优化形式也越来越显得顾此失彼。当一个长期运行的 Spark 利用,若调配给它多个 Executor,可是却没有任何 task 调配到这些 Executor 上,而此时有其余的 Spark 利用却资源缓和,这就造成了资源节约和调度不合理。
要是每个 Spark 利用的 Executor 数也能动静调整那就太好了。
动静资源分配(Dynamic Resource Allocation)就是为了解决这种场景而产生。Spark 2.4 版本中 on Kubernetes 的动静资源并不欠缺,在 Spark 3.0 版本欠缺了 Spark on Kubernetes 的性能,其中就包含更灵活的动态分配。咱们 Erda 的 FDP 平台(Fast Data Platform)从 Spark 2.4 降级到 Spark 3.0,也尝试了动静资源分配的相干优化。本文将针对介绍 Spark 3.0 中 Spark on Kubernetes 的动静资源应用。
原理
一个 Spark 利用中如果有些 Stage 略微数据歪斜,那就有大量的 Executor 是闲暇状态,造成集群资源的极大节约。通过动静资源分配策略,曾经闲暇的 Executor 如果超过了肯定工夫,就会被集群回收,并在之后的 Stage 须要时可再次申请 Executor。
如下图所示,固定 Executor 个数状况,Job1 End 和 Job2 Start 之间,Executor 处于闲暇状态,此时就造成集群资源的节约。
</center>
开启动静资源分配后,在 Job1 完结后,Executor1 闲暇一段时间便被回收;在 Job2 须要资源时再申 Executor2,实现集群资源的动静治理。
动态分配的原理很容易了解:“按需应用”。当然,一些细节还是须要思考到:
- 何时新增 / 移除 Executor
- Executor 数量的动静调整范畴
- Executor 的增减频率
- Spark on Kubernetes 场景下,Executor 的 Pod 销毁后,它存储的两头计算数据如何拜访
这些留神点在上面的参数列表中都有相应的阐明。
参数一览
spark.dynamicAllocation.enabled=true #总开关,是否开启动静资源配置,依据工作负载来掂量是否应该减少或缩小 executor,默认 false
spark.dynamicAllocation.shuffleTracking.enabled=true #spark3 新增,之前没有官网反对的 on k8s 的 Dynamic Resouce Allocation。启用 shuffle 文件跟踪,此配置不会回收保留了 shuffle 数据的 executor
spark.dynamicAllocation.shuffleTracking.timeout #启用 shuffleTracking 时管制保留 shuffle 数据的 executor 超时工夫,默认应用 GC 垃圾回收管制开释。如果有时候 GC 不及时,配置此参数后,即便 executor 上存在 shuffle 数据,也会被回收。暂未配置
spark.dynamicAllocation.minExecutors=1 #动态分配最小 executor 个数,在启动时就申请好的,默认 0
spark.dynamicAllocation.maxExecutors=10 #动态分配最大 executor 个数,默认 infinity
spark.dynamicAllocation.initialExecutors=2 #动态分配初始 executor 个数默认值 =spark.dynamicAllocation.minExecutors
spark.dynamicAllocation.executorIdleTimeout=60s #当某个 executor 闲暇超过这个设定值,就会被 kill,默认 60s
spark.dynamicAllocation.cachedExecutorIdleTimeout=240s #当某个缓存数据的 executor 闲暇工夫超过这个设定值,就会被 kill,默认 infinity
spark.dynamicAllocation.schedulerBacklogTimeout=3s #工作队列非空,资源不够,申请 executor 的工夫距离,默认 1s(第一次申请)spark.dynamicAllocation.sustainedSchedulerBacklogTimeout #同 schedulerBacklogTimeout,是申请了新 executor 之后持续申请的距离,默认 =schedulerBacklogTimeout(第二次及之后)spark.specution=true #开启揣测执行,对长尾 task,会在其余 executor 上启动雷同 task,先运行完结的作为后果
实战演示
无图无假相,上面咱们将动静资源分配进行简略演示。
1. 配置参数
动静资源分配相干参数配置如下图所示:
如下图所示,Spark 利用启动时的 Executor 个数为 2。因为配置了
spark.dynamicAllocation.initialExecutors=2
<center></center>
运行一段时间后成果如下,executorNum 会递增,因为闲暇的 Executor 被一直回收,新的 Executor 一直申请。
2. 验证快慢 SQL 执行
应用 SparkThrfitServer 会遇到的问题是一个数据量很大的 SQL 把所有的资源全占了,导致前面的 SQL 都期待,即便前面的 SQL 只须要几秒就能实现。咱们开启动态分配策略,再来看 SQL 执行程序。
先提交慢 SQL:
再提交快 SQL:
如下图所示,开启动静资源分配后,因为 SparkThrfitServer 能够申请新的 Executor,前面的 SQL 无需期待便可执行。Job7(慢 SQL)还在运行中,后提交的 Job8(快 SQL)已实现。这在肯定水平上缓解了资源分配不合理的状况。
3. 详情查看
咱们在 SparkWebUI 上能够看到动态分配的整个流程。
登陆 SparkWebUI 页面,Jobs -> Event Timeline,能够看到 Driver 对整个利用的 Executor 调度。如下图所示,显示了每个 Executor 的创立和回收。
同时也能看到此 Executor 的具体创立和回收工夫。
在 Executors 标签页,咱们能够看到所有历史 Executor 的以后状态。如下图所示,之前的 Executor 都已被回收,只有 Executor-31 状态为 Active。
总结
动静资源分配策略在闲暇时开释 Executor,忙碌时申请 Executor,尽管逻辑比较简单,然而和任务调度密切相关。它能够避免小数据申请大资源,Executor 空转的状况。在集群资源缓和,有多个 Spark 利用的场景下,能够开启动态分配达到资源按需应用的成果。
以上是咱们在 Spark 相干优化的一点教训,心愿可能对大家有所帮忙😄。
注:文中局部图片源自于网络,侵删。
更多技术干货请关注【尔达 Erda】公众号,与泛滥开源爱好者独特成长~