我有一个应用程序通过RemoteExecutionEnvironment
scala API将Apache Flink作业分派到AWS Elastic MapReduce YARN群集。
这些作业使用JNI通过C库运行部分计算。在开发过程中,我只是在System.loadLibrary()
RichCrossFunction
方法中调用open()
来加载此JNI库。这在LocalExecutionEnvironment
中运行良好。
现在我转移到RemoteExecutionEnvironment
这似乎不再适用了。看起来Flink每次调度作业时都使用新的ClassLoader
,并且我在计算节点上出现Native library already loaded in another classloader
错误。
一些谷歌搜索告诉我,这是Tomcat应用程序的常见问题,Tomcat FAQ中提供了一个解决方案:http://wiki.apache.org/tomcat/HowTo#I.27m_encountering_classloader_problems_when_using_JNI_under_Tomcat
Flink或YARN是否有类似的解决方案?
此外,是否可以避免每次作业排队时重新提交JAR?我总是在这个集群上使用相同的jar,所以这是不必要的开销......
答案 0 :(得分:2)
我通过在JNI jar中的静态初始化程序中调用loadLibrary
来修复此问题,然后将我的JNI jar放入Flink的/lib
文件夹中,类似于上面Tomcat链接中的模式
它通过yarn-session.sh
启动过程自动复制到Flink TaskManagers。这使我能够以与使用Tomcat相同的方式规避ClassLoader
隔离。
我使用Maven,所以我使用maven-shade-plugin防止JNI jar被包含在我的uberjar中。
我仍然不知道这是否是最好的方式,因为flink手册不鼓励使用/lib
文件夹,因为它不尊重他们的ClassLoader管理(https://ci.apache.org/projects/flink/flink-docs-release-1.0/apis/cluster_execution.html),但这正是我想要的。
也许另一种方法是使用NativeLoader模式并为每个ClassLoader创建一个单独的临时文件,但这会创建一堆重复的本机库,这个方法对我有用。