如何在YARN集群模式下通过spark-submit向Scala编写的Spark程序传递本地文件路径
解决YARN Cluster模式下Spark读取本地文件失败的问题
我来帮你分析问题根源,再给出针对性的解决方案:
问题核心原因
你遇到的问题本质是YARN Cluster模式的运行机制差异:当使用--deploy-mode cluster提交任务时,Spark Driver会运行在YARN集群的某个Worker节点上,而不是你执行spark2-submit命令的本地Linux服务器。
- 第一次尝试用
--files ${csv_file}时,Cluster模式下Spark默认会把路径解析为HDFS路径,所以它去HDFS根目录查找文件,自然找不到本地机器上的文件。 - 第二次传命令行参数的方式,虽然代码能拿到路径,但Driver所在的集群节点上并没有
/usr/usr1/Test.csv(这个文件只存在于你提交命令的本地机器),因此依然报错。
可行解决方案
根据你的需求,有两种常用的解决方式,可根据场景选择:
方案1:将文件上传到HDFS(推荐)
这是最稳妥的方案,尤其适合大文件或需要重复使用的场景:
- 先把本地文件上传到HDFS:
hdfs dfs -put /usr/usr1/Test.csv /user/your-username/Test.csv - 修改提交命令,传入HDFS路径作为参数:
csv_file="hdfs:///user/your-username/Test.csv" spark2-submit \ --num-executors 30 \ --driver-memory 12g \ --executor-memory 14g \ --executor-cores 4 \ --class driver_class \ --name TTTTTT \ --master yarn \ --deploy-mode cluster \ --files myprop.properties \ abc.jar ${csv_file} - 代码无需额外修改,保持用
args(0)获取路径即可——HDFS路径在整个集群都能正常访问。
方案2:利用Spark分布式缓存(--files参数)
如果你的文件很小,或者不想上传到HDFS,可以用--files将本地文件分发到所有Driver和Executor节点的分布式缓存中:
- 修改代码,通过
SparkFiles.get()获取缓存后的文件路径:import org.apache.spark.SparkFiles def main(args: Array[String]) { val spark = SparkSession.builder.appName("SparkData").getOrCreate() val sc = spark.sparkContext sc.setLogLevel("ERROR") import spark.implicits._ // 从分布式缓存中获取文件,参数是文件名而非原本地路径 val filepath = SparkFiles.get("Test.csv") val df = spark.read.format("csv").load(filepath) df.show() spark.stop() } - 修改提交命令,将本地文件路径加入
--files参数:
这里不需要传命令行参数,Spark会自动把spark2-submit \ --num-executors 30 \ --driver-memory 12g \ --executor-memory 14g \ --executor-cores 4 \ --class driver_class \ --name TTTTTT \ --master yarn \ --deploy-mode cluster \ --files myprop.properties,/usr/usr1/Test.csv \ abc.jar/usr/usr1/Test.csv复制到每个节点的临时目录,你只需要用文件名Test.csv通过SparkFiles.get()获取实际路径即可。
注意事项
- 如果文件体积较大,不推荐方案2,因为
--files会把文件复制到每个集群节点,占用额外存储资源,此时方案1(HDFS)更高效。 - 永远记住:Cluster模式下Driver不在本地机器,任何本地路径的引用都要确保集群节点能访问到——要么通过分布式缓存分发,要么使用共享存储(如HDFS)。
内容的提问来源于stack exchange,提问作者VnS
相关产品推荐
相关产品推荐

