分享

在Hadoop集群运行JNI实例程序指导

hyj 2014-1-29 01:40:44 发表于 实操演练 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 7522
本帖最后由 hyj 于 2014-1-29 02:09 编辑

hadoop是基于java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力。 阿里巴巴内部使用的分词软件(用c++实现的,以下简称WS包)是日常工作中最基本的软件包,通过java的jni机制,笔者将WS包成功的运行在hadoop上,深受很多部门的欢迎。下面借这个例子介绍hadoop上jni程序的开发过程。

首先,简单介绍一下WS包中的调用接口和基本结构。  WS包包括词典文件A.dict,对外提供静态链接库文件libWS.a。WS.h如下:
  1. Class WS{
  2. int init(const char* name);
  3. int segment(char* dest, char* src, int len,int kind);
  4. }
复制代码
我们的方案是首先生成jni的原型定义,然后根据原型定义,来包装WS类的接口,最后生成可在tasknode上运行的jni程序包。结构如下图所示

第一步,我们先使用java的jni技术,生成C的原型接口(prototype),然后编写Wsjni.java 文件,这是为云梯程序提供的类文件,其中libwsjni.so 就是wrapper类的动态链接库:
  1. Class Wsjni{
  2. Public Native int init(String conf);
  3. Public Native String segment(String src,int kind);
  4. Public Native void close();  //用于显示的释放内存
  5. Static{
  6. System.LoadLibrary(“libwsjni.so”); //  load 链接库
  7. }
  8. }
复制代码
  1. javac -d class Wsjni.java  //产生class文件
  2. javah -classpath ./class ws.Wsjni  //这样就可以生成C的原型接口头文件Wsjni.h
复制代码
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是否正确。
  1. Import Wsjni;
  2. Class Test{
  3. Public static void main(){
  4. Wsjni ws=new Wsjni();
  5. Ws.init(“taobao.conf”);
  6. Ws.segment(“你好淘宝”,1);
  7. Ws.close();
  8. }
  9. }
复制代码
运行命令是
  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
复制代码
第三步,在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
复制代码
这样的目录结构,使得程序访问文件的路径一目了然,当调用者需要调用WS的接口时,词典A.dict和libwsjni.so 都在./ws 目录下。

因此,调用者的代码如下:
  1. Mapper(){
  2. Wsjni  wsjni=new Wsjni();
  3. Public void configure( ){
  4. Wsjni.init("./ws/taobao.conf”,1);
  5. }
  6. Public mapper(){
  7. Wsjni.segment(sentence,2);
  8. }
  9. Public close(){
  10. Wsjni.close();
  11. }
  12. }
  13. Run(){
  14. Jobconf.set(“java.library.path”,”./ws”);
  15. DistributedCache.addCacheArchive(“hdfs://file_path/ws.jar#ws”,conf);
  16. }
复制代码
需要设置 lava.library.path的原因是,java虚拟机需要找到libwsjni.so存放的路径。有必要通过ldd 命令看看so依赖哪些库,保证这些库和hadoop集群的tasknode中的库的版本一致。



来自群组: Hadoop技术组

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条