1. Spark的动态资源分配

动态资源分配:Dynamic resource allocation

资料详见:https://mp.weixin.qq.com/s?__biz=MzU4MDkzMDE4Nw==&mid=2247490009&idx=1&sn=e9e728b4cb620eb7d98eabcc32fe5c0e&chksm=fd4e063dca398f2b10a0ea1a367364ff6aa15a8564070fc9c2c1fe271941b51b3e700249e210&mpshare=1&scene=1&srcid=0114SJNB2iyqCPeco1YFKV6O&sharer_sharetime=1642124675169&sharer_shareid=5a0f351a09ba9e634c5da47fc318805e&version=4.0.0.6007&platform=win#rd

通过spark.dynamicAllocation.enabled参数开启后就会启动ExecutorAllocationManager

触发条件

添加Worker的触发条件是:

  • 有Stage正在运行,并且预估需要的Executors > 现有的

    删除Woker的触发条件是:

  • 一定时间内(默认60s)没有task运行的Executor

    我们看到触发条件还是比较简单的。这种简单就意味着用户需要根据实际场景,调整各个时间参数,比如到底多久没有运行task的Executor才需要删除。
    默认检测时间是100ms:
    private val intervalMillis: Long = 100

资源释放策略

如果executor闲置时间超过以下参数,则spark应用将会释放该executor。
# 默认60秒 spark.dynamicAllocation.executorIdleTimeout(单位为秒)

executor cache重算问题

除了shuffle,executor中还有可能将数据缓存在磁盘或者内存中,而executor一旦退出,这些cache将不再能够访问。这些cache存储的时长由以下参数决定:
# 默认为infinity,永远不删除 spark.dynamicAllocation.cachedExecutorIdleTimeout(单位为秒)。比如在spark-shell中先前cache了一个df,该cache不释放情况下,就算当前没有task运行,资源也不会释放。

Shuffle输出重算问题

在没有开启Dynamic Allocation时,如果执行失败、或者与其关联的JOB退出时结束Spark应用。这两种情况下,所有与之关联的状态将会安全的被丢弃。但如果开启了Dynamic Allocation,会存在Spark应用仍在运行,但executor被显式地释放的情况。例如:某个任务执行比较慢,而其他的任务执行比较快,那么这些任务对应的executor会被释放。
此时,如果应用程序尝试访问存储在executor中的状态,就会导致之前已经SUCCESS的任务需要重新计算。所以,需要在退役executor之前,保存其状态来优雅退役executor,释放资源。这项操作对于有shuffle的应用尤其重要。在shuffle期间,Spark executor先要将map的输出写入到磁盘,然后该executor充当一个文件服务器,将这些文件共享给其他的executor访问。所以,如果开启Dynamic Allocation时,不能继续把Shuffle的状态保存在executor中,要让shuffle的输出保留,供其他的executor读取。Spark引入了Spark-extenal-serveice解决该问题。
资料详见:https://mp.weixin.qq.com/s?__biz=MzU4MDkzMDE4Nw==&mid=2247490064&idx=1&sn=0632820d1d8e313a97f633bb7a995c8f&chksm=fd4e05f4ca398ce2513dfb5e093d3aa2900acf83cc12fe7b5e6c3d49df4bedbcd01243059eff&mpshare=1&scene=1&srcid=0225rvA3AG05N9tpSXTamlMY&sharer_sharetime=1645785238882&sharer_shareid=5a0f351a09ba9e634c5da47fc318805e&version=4.0.0.6007&platform=win#rd

Spark内存模型

钨丝计划(Tungsten On Spark)

Project Tungsten由DataBricks提出,并在Spark1.5中引入,在1.6.X对内存进行了优化,在2.X对CPU进行了优化,也就是说该项目主要是针对于CPU和Memory进行优化,具体优化集中在以下三个方面:

  1. Memory Management And Binary Processing(内存管理和二进制处理)
  2. Cacahe-aware Computation(缓存感知计算):使用了友好的数据结构和算法来完成数据的存储和复用,提升缓存命中率
  3. Code Generation(代码生成):扩展了更多的表达式求值和SQL操作,把已有的代码变成本地的字节,不需要很多的抽象和匹配等,避免了昂贵的虚拟函数调用