val conf = new SparkConf()
.set("spark.locality.wait", "6")
Spark 作业运行过程中, Driver 会对每一个 stage 的 task 进行分配。 根据 Spark的 task 分配算法, Spark 希望 task 能够运行在它要计算的数据所在的节点(数据本地化思想), 这样就可以避免数据的网络传输。通常来说, task 可能不会被分配到它处理的数据所在的节点,因为这些节点可用的资源可能已经用尽,此时, Spark会等待一段时间,默认 3s, 如果等待指定时间后仍然无法在指定节点运行,那么会自动降级,尝试将 task 分配到比较差的本地化级别所对应的节点上, 比如将 task 分配到离它要计算的数据比较近的一个节点,然后进行计算, 如果当前级别仍然不行,那么继续降级。
当 task 要处理的数据不在 task 所在节点上时, 会发生数据的传输。 task 会通过所在节点的 BlockManager 获取数据, BlockManager 发现数据不在本地时,户通过网络传输组件从数据所在节点的 BlockManager 处获取数据。网络传输数据的情况是我们不愿意看到的,大量的网络传输会严重影响性能,因此,我们希望通过调节本地化等待时长, 如果在等待时长这段时间内, 目标节点处理完成了一部分 task,那么当前的 task 将有机会得到执行,这样就能够改善 Spark作业的整体性能。
PROCESS_LOCAL | 进 程 本 地 化 , task 和 数 据 在 同 一 个Executor 中, 性能最好。 |
NODE_LOCAL | 节点本地化, task 和数据在同一个节点中, 但是 task 和数据不在同一个 Executor中,数据需要在进程间进行传输。 |
RACK_LOCAL | 机架本地化, task 和数据在同一个机架的两个节点上,数据需要通过网络在节点之间进行传输。 |
NO_PREF | 对于 task 来说,从哪里获取都一样,没有好坏之分。 |
ANY | task 和数据可以在集群的任何地方,而且不在一个机架中,性能最差。 |
在 Spark 项目开发阶段,可以使用 client 模式对程序进行测试,此时,可以在本地看到比较全的日志信息,日志信息中有明确的 task 数据本地化的级别,如果大部分都是 PROCESS_LOCAL,那么就无需进行调节,但是如果发现很多的级别都是NODE_LOCAL、 ANY,那么需要对本地化的等待时长进行调节,通过延长本地化等待时长,看看 task 的本地化级别有没有提升,并观察 Spark 作业的运行时间有没有缩短。
注意, 过犹不及,不要将本地化等待时长延长地过长,导致因为大量的等待时长,使得 Spark 作业的运行时间反而增加了。