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 对应的环境目录下,相对麻烦一些。

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...