C++ / JNI - Spark 调用 JNI on Yarn
创始人
2024-05-07 08:11:57
0

一.引言

前面介绍了如何使用 C++ 与 Java  构建自己的 .so 包并实现了本地的测试,下面介绍如何在 Yarn 集群使用 Spark 调用 JNI 函数。

二.JNI TestOnYarn 实现逻辑

介绍之前,首先回顾一下之前本地测试是如何实现的:

// 加载 .so
System.load(filePath)
// 初始化对应类
TestJNIByJVM testJNIByJVM = new TestJNIByJVM();
// JNI 方法调用
int res = testJNIByJVM.testJNI(input1, input2);

切换到 Spark On Yarn 后,所以我们需要注意三个事情:

A.如何传输文件

由于 Spark On Yarn 运行在分布式环境,所以不能像本地测试一样,在本机存储一份文件即可,需要使用 --files 参数将对应动态库 .so 包分布式传到每一台机器。这一步需要在 Spark Submit 脚本处实现:

--files ${libSoPath} \

如果你的任务本身已经 --files 传了文件,则你需要逗号分隔传递多个文件:

--files ${OtherFile},${LibSoPath} \

如果更多的话,依次类推,就像 --jars 一样传输多个 jar。 

B.如何读取文件

不论是本地测试还是集群测试,这里都推荐使用 Load 方法传递绝对路径读取,而 LoadLibrary 方法读取绝对路径虽然代码量会少一点,但是容易出去出现异常,所以建议前者。前面我们写过 Spark Submit --files 文件读取,大家可以参考其中方法:

SparkFiles.get(fileName)

其中 fileName 为 --files 传输的文件名,通过该方法可以在 Driver 端或者 Executor 端获取该文件在分布式执行机器上的对应存储位置,再使用 System.load 读取绝对路径即可,当然也可以直接使用 System 方法直接本机地址:

System.getenv("PWD")

C.调用方法

由于需要后期传入 Path 再读取,所以不能像上面那样初始化 Object 静态类时直接 System.load,我们需要为当前类提供 init 方法,并在 Driver 端或者 Executor 端调用 init 方法初始化:

- 本地

// 加载 .so
System.load(filePath)
// 初始化对应类
TestJNIByJVM testJNIByJVM = new TestJNIByJVM();

- Spark

这里使用变量初始化 JNI 类为 null,并提供 init 方法供 Dirver、Executor 端调用。

object TestJNI {// 初始化默认空值var testJNIByJVM: TestJNIByJVM = _// 根据 path Loaddef initJNI(filePath: String): Unit = {if (testJNIByJVM == null) {System.load(filePath);testJNIByJVM = new TestJNIByJVM()println("初始化 TestJNI!")} else {println("已初始化 TestJNI!")}}}

D.Dirver、Executor 调用

就是 JNI 调用是在 Driver 端还是 Executor 端,不管哪一端调用都需要对应的初始化方法,而不是 Driver 端初始化一劳永逸。

- Driver

      val libPath = s"${System.getenv("PWD")}/xxx.so"TestJNI.initJNI(libPath)

这一步调用方法是介于 SparkContext 与 RDD 执行逻辑之间,因为你要在 Driver 端调用。

- Executor

Executor 端初始化方法相同,唯一区别是需要将上述在 RDD 逻辑内初始化,建议大家使用 foreachPartition 和 mapPartition 减少初始化次数,当然也可以在 Executor 端加锁或者使用双重检测等等,总之不要初始化太多次浪费时间。

    rdd.foreachPartition(partition => {val libPath = s"${System.getenv("PWD")}/xxx.so"TestJNI.initJNI(libPath) while (partition.hasNext) {...}})

加载成功后,调用静态类变量方法即可,Func 即为你 JNI 实现的方法:

TestJNI.TestJNIByJVM.Func

三.总结

相比本地或者单服务器调用,Spark On Yarn 调用需要多一个步骤,但是整体思路不变,这里还是再次推荐一下使用 load 方法读取绝对路径,如果想要调用绝对路径,需要把 .so 包放到 spark 对应的环境目录下,相对麻烦一些。

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...