我有一个应用程序通过 RemoteExecutionEnvironment
scala API 将 Apache Flink 作业分派(dispatch)到 AWS Elastic MapReduce YARN 集群。
这些作业使用 JNI 通过 C 库运行部分计算。在开发过程中,我只是在 RichCrossFunction
的 open()
方法中调用了一个 System.loadLibrary()
来加载这个 JNI 库。这在 LocalExecutionEnvironment
中运行良好。
现在我要转到 RemoteExecutionEnvironment
这似乎不再有效。看起来 Flink 每次分派(dispatch)作业时都在使用新的 ClassLoader
并且我在计算节点上收到 Native library already loaded in another classloader
错误。
谷歌搜索告诉我这是 Tomcat 应用程序的常见问题,Tomcat 常见问题解答中提供了解决方案:http://wiki.apache.org/tomcat/HowTo#I.27m_encountering_classloader_problems_when_using_JNI_under_Tomcat
Flink 或 YARN 是否有类似的解决方案?
此外,是否可以避免每次作业排队时都重新提交 JAR?我总是在这个集群上使用同一个 jar,所以这是不必要的开销......
最佳答案
我通过在我的 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 创建一个单独的临时文件,但这会创建一堆重复的 native 库,这种方法适合我。
关于java - 在 flink YARN 集群作业中使用 JNI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38267836/