IT技术博客大学习 共学习 共进步

如何在Hadoop集群运行jni程序

搜索技术博客-淘宝 2010-12-23 22:40:01 浏览 2,922 次
    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. Facebook的实时Hadoop系统 (阅读 11,401)
  2. hadoop rpc机制 && 将avro引入hadoop rpc机制初探 (阅读 6,081)
  3. Hadoop的map/reduce作业输入非UTF-8编码数据的处理原理 (阅读 5,545)
  4. 百度是如何使用hadoop的 (阅读 5,004)
  5. Hadoop超级安装手册 (阅读 4,660)
  6. Hadoop集群间Hadoop方案探讨 (阅读 4,441)
  7. 使用hadoop进行大规模数据的全局排序 (阅读 4,422)
  8. Hadoop安装端口已经被占用问题的解决方法 (阅读 3,880)
  9. Hadoop现有测试框架探幽 (阅读 3,802)
  10. 分布式计算平台Hadoop 发展现状乱而稳定的解读 (阅读 3,803)