本篇我们讨论一下数据本地化等待时长调节的优化。在介绍关于本地化等待时长调节之前,我们先来看看数据本地化的运行原理吧。
Spark在Driver上对Application的每个task任务进行分配之前,都会先计算出每个task要计算的对应的数据分片的位置。Spark的task分配算法优先考虑将task分配到分片数据所在的节点,以此来避免网络间数据传输带来的性能消耗。但是在实际的生产环境并不是我们所想象的那样,有可能某些task没有机会把它分配到其所要计算的数据所在的节点;为什么会发生这种情况呢?其实是因为某些节点的计算资源都已经被占用完了;在这个时候,task会等待一段时间,默认情况是3s,等待时间过了以后,还是没有轮到其执行,task就会去选择一种比较差的本地化级别(本地化级别会在后面介绍)去执行。但是选择了其他的本地化级别就会出现网络数据传输的情况;比如说,task会通过其所在节点的BlockManager中获取数据,但是BlockManager中并没有所需要的数据,这个时候BlockManager会通过getRemote()方法,利用TransferService(网络数据传输组件)从附近节点去拷贝数据到本地的BlockManager中供task使用。下面通过一幅图来形象的说明一下;
Case1:同一个机架中,不同的Worker节点;
Case2:同一个机架,同一个Worker节点,不同Executor进程间;
Case3:不同机架间数据的拷贝;
结合上面的几种情况,介绍一下数据本地化的几种级别:
PROCESS_LOCAL:进程本地化,代码和数据在同一个进程中,也就是在同一个executor中;计算数据的task由executor执行,数据在executor的BlockManager中;性能最好(图1)
RACK_LOCAL:机架本地化,数据和task在一个机架的两个节点上;数据需要通过网络在节点之间进行传输(图2)
NODE_LOCAL:节点本地化,代码和数据在同一个节点中;比如说,数据作为一个HDFSblock块,就在节点上,而task在节点上某个executor中运行;或者是,数据和task在一个节点上的不同executor中;数据需要在进程间进行传输(图3)
ANY:数据和task可能在集群中的任何地方,而且不在一个机架中,性能最差(图4)
NO_PREF:对于task来说,数据从哪里获取都一样,没有好坏之分
讲了很多理论,现在来说说我们在什么情况下调节数据本地化等待时长这个参数?在项目该如何使用?
在什么情况下调节数据本地化等待时长这个参数?
观察日志,spark作业的运行日志,推荐大家在测试的时候,先用client模式,在本地就直接可以看到比较全的日志。日志里面会显示,starting task。。。,PROCESSLOCAL、NODE、LOCAL观察大部分task的数据本地化级别,如果大多都是PROCESS_LOCAL,就没有调节的必要。如果是发现,好多的级别都是NODE_LOCAL、ANY,那么最好就去调节一下数据本地化的等待时长调节完,应该是要反复调节,每次调节完以后,再来运行,观察日志看看大部分的task的本地化级别有没有提升;看看,整个spark作业的运行时间有没有缩短。
在项目该如何使用?
通过 spark.locality.wait 参数进行设置,默认为3s,6s,10s。
项目中代码展示:
new SparkConf().set("spark.locality.wait","10");
总结:本文关于使用数据本地化等待时长调优到这里基本接近尾声,后续还会不断更新关于Spark作业优化的一些其他方式,欢迎关注。
如需转载,请注明: