Spark执行任务Locality Level总是为ANY的问题

总所周知,分布式计算系统为了保证性能都是移动计算而非移动数据,在Spark系统中执行任务也是遵循这个原则,RDD中有个preferredLocations记录了当前要处理的数据的最佳位置。Spark性能调优也有个关键因素即:Data Locality,具体可以参考:http://spark.apache.org/docs/latest/tuning.html#data-locality

最近在处理集群查询性能的过程中发现很多读取数据的Task的Locality Level总是为Any,也就是说在Spark中跑任务几乎都要走网络拷贝数据,我们在测试环境执行select count(1) from test这样的一个非常简单的查询也有大量的网络IO(可以通过dstat观察到,test表大约18G,Spark集群只有不到10台,每台机器都有相应的数据块),按理说Locality Level都应该为NODE_LOCAL才对,而且select count这样的操作也不存在shuffle,理论来说不会有这么大的网络开销。

集群管理器用的是Spark Standalone,后来从Spark Master的Web UI中发现Worker的Address和Hadoop中显示的不一致,一个为主机名,一个为ip地址。看了下Spark的源代码(org/apache/spark/scheduler/TaskSetManager.scala),发现Spark在分发任务的时候,或调用Hadoop的API得到文件在所服务器的信息,这个信息需要和Spark的Executor的保持一致才能正常分发。也就是说,如果hadoop的datanode列表中显示的是主机名,那么Executor启动时也要按主机名的方式启动。

最后为Executor单独设置了ip的方式,在次执行任务,Locality Level都为NODE_LOCAL了。

PS:最近发现Spark 1.6以上的版本已经没有这个问题了,使用1.6以下的版本需要注意下。