我正在尝试在运行spark作业时使用外部本机库(.so文件)。首先,我使用--files
参数提交文件。
在创建System.load(SparkFiles.get(libname))
之后加载我正在使用SparkContext
的库(以确保填充SparkFiles
)。
问题是该库仅由驱动程序节点加载,并且当任务尝试访问我正在获取的本机方法时
WARN TaskSetManager: Lost task 0.0 in stage 2.0 (TID 2, 13.0.0.206, executor 0): java.lang.UnsatisfiedLinkError
对我来说唯一有用的是在运行spark应用程序之前将.so
文件复制到所有工作程序,并创建一个Scala对象,该对象将在每个任务之前加载库(可以使用{{1进行优化) }})。
我尝试使用
mapPartitions
试图避免这种情况,但没有成功。
现在,因为我正在使用EMR来运行spark作业,而不是一致的集群, 我想避免在运行作业之前将文件复制到所有节点。
有什么建议吗?
答案 0 :(得分:2)
解决方案比我想象的要简单 - 我需要的是每个JVM加载一次库
基本上我需要的是使用--files
添加库文件并创建一个Loader对象:
object LibraryLoader {
lazy val load = System.load(SparkFiles.get("libname"))
}
并在每项任务(map
,filter
等)之前使用它。)
例如
rdd.map { x =>
LibraryLoader.load
// do some stuff with x
}
懒惰将确保在填充SparkFiles之后创建对象,并且还确保每个JVM进行单一评估。