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

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...