IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

如何在Hadoop集群运行jni程序

搜索技术博客-淘宝 2010-12-23 22:40:01 累计浏览 2,999 次
本机暂存
    Hadoop是基于Java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力。 阿里巴巴内部使用的分词软件(用C++实现的,以下简称WS包)是日常工作中最基本的软件包,通过Java的jni机制,笔者将WS包成功的运行在Hadoop上,深受很多部门的欢迎。下面借这个例子介绍Hadoop上jni程序的开发过程。

     首先,简单介绍一下WS包中的调用接口和基本结构。  WS包包括词典文件A.dict,对外提供静态链接库文件libWS.a。WS.h如下:

 
1 Class WS{
2   
3         int init(const char* name);
4   
5         int segment(char* dest, char* src, int len,int kind);
6 }

我们的方案是首先生成jni的原型定义,然后根据原型定义,来包装WS类的接口,最后生成可在tasknode上运行的jni程序包。结构如下图所示

原图已失效

    第一步,我们先使用java的jni技术,生成C的原型接口(prototype),然后编写Wsjni.java 文件,这是为云梯程序提供的类文件,其中libwsjni.so 就是wrapper类的动态链接库:

 
01 Class Wsjni{
02   
03         Public Native int init(String conf);
04   
05         Public Native String segment(String src,int kind);
06   
07         Public Native void close(); //用于显示的释放内存
08   
09         Static{
10   
11                 System.LoadLibrary(“libwsjni.so”); // load 链接库
12         }
13 }

产生class文件

 
1 Javac -d class Wsjni.java

这样就可以生成C的原型接口头文件Wsjni.h

 
1 javah -classpath ./class ws.Wsjni

Wsjni.h里面的有函数的原型声明,例如:

 
1 JNIEXPORT jint JNICALL Java_ws_Wsjni_ws_1init__Ljava_lang_String_2(JNIEnv *, jobject, jstring);

第二步,根据Wsjni.h实现wrapper类。需要阅读sun公司编写的jni的规范来实现应用,具体不在这里赘述。在Makefile中链接静态库libWs.a,从而生成一个动态的链接库libwsjni.so ,

 
1 g++ -g -o ./class/libwsjni.so -fPIC -shared -Wl,-soname,./class/libWsjni.so ws_Wsjni.cpp -I./include -Wl,-Bstatic -lWs -L./lib/ -Wl,-Bdynamic

我们的wrapper类就写好了。我们可以通过java的程序来测试验证jni是否正确。

 
01 Import Wsjni;
02   
03 Class Test{
04   
05         Public static void main(){
06   
07                 Wsjni ws=new Wsjni();
08   
09                 Ws.init(“taobao.conf”);
10   
11                 Ws.segment("你好淘宝", 1);
12   
13                 Ws.close();
14         }
15 }

运行命令是:

 
1 Java -cp ./class -D java.liabray.path=./class Test

为了在Hadoop上运行Ws包,需要制作两个jar包,一个是wsjni.jar, 通过-libjar选项提供class文件; 一个用于Hadoop集群运行,ws.jar里面放了Ws包运行时需要的资源文件,包括链接库和词典文件。Wsjni.jar中的文件是:

 
1 ./ Wsjni.class

Ws.jar 中的文件是:

 
1 ./A.dict
2 ./libwsjni.so
3 ./taobao.conf

第三步,在Hadoop上调用Wsjni。Hadoop有很特殊的文件系统,这里笔者针对性介绍一下DistributeCache的机制。Hadoop可以将HDFS的一些文件分发到运行的某台机器的工作目录下,并按照一定的逻辑解压。通过以下API实现:

 
1 DistributedCache.addCacheArchive(“hdfs://file_path/ws.jar#ws”,conf);

上面的API将ws.jar分发到tasknode上,并解压到工作目录的link目录下。Ws.jar包含ws相关的资源文件。在tasknode上,每个task工作目录下的文件是:

 
1 Jars/
2 Jars/yourJob.cass
3 ws/
4 ws/A.dict
5 ws/libwsjni.so
6 ws/taobao.conf

这样的目录结构,使得程序访问文件的路径一目了然,当调用者需要调用WS的接口时,词典A.dict和libwsjni.so 都在./ws 目录下。

因此,调用者的代码如下:

 
01 Mapper(){
02   
03         Wsjni wsjni=new Wsjni();
04   
05         Public void configure( ){
06   
07                 Wsjni.init("./ws/taobao.conf”,1);
08   
09         }
10   
11         Public mapper(){
12   
13                 Wsjni.segment(sentence,2);
14   
15         }
16   
17         Public close(){
18   
19                 Wsjni.close();
20   
21         }
22   
23 }
24   
25 Run(){
26   
27         Jobconf.set(“java.library.path”,”./ws”);
28   
29         DistributedCache.addCacheArchive(“hdfs://file_path/ws.jar#ws”,conf);
30   
31 }

需要设置 lava.library.path的原因是,java虚拟机需要找到libwsjni.so存放的路径。有必要通过ldd 命令看看so依赖哪些库,保证这些库和Hadoop集群的tasknode中的库的版本一致。

罗嗦了这么多,都是细节问题,还得各位手动再做一遍,Hadoop的程序不太方便调试,但是遇到的困难越多,收获的越多。呵呵。

欢迎各位不吝赐教。

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. SmartSprites - 命令行形式的CSS Sprites生成器 (累计阅读 123,895)
  2. Java开发岗位面试题归类汇总 (累计阅读 22,157)
  3. android 开发入门 (累计阅读 19,529)
  4. HFile存储格式 (累计阅读 15,977)
  5. 我的PHP,Python和Ruby之路 (累计阅读 13,149)
  6. HashMap解决hash冲突的方法 (累计阅读 12,654)
  7. Zookeeper工作原理 (累计阅读 12,203)
  8. Facebook的实时Hadoop系统 (累计阅读 11,495)
  9. 一个大二学生有关如何成为一名软件工程师的疑问及答复 (累计阅读 9,181)
  10. HBase技术介绍 (累计阅读 8,077)