hadoop是Java实现的一个分布式框架,在大数据和云计算等方面都有广泛的应用。众所周知,C++比Java更偏向底层,C++在数据读写方面比Java更有优势;一般来讲,C++的执行效率比由JVM解释执行的Java效率高。那么,在一些频繁读取数据而且对程序性能要求很高的mapreduce程序中,将map任务和reduce任务用C++来编写,也许会是一种更好的选择。这就Hadoop pipes编程技术的由来。Hadoop pipes允许用户用C++编写mapreduce程序,这个C++程序在执行Hadoop任务时会被作为一个单独的进程,Hadoop框架会利用socket套接字来让Java和C++程序进行通信,这样就实现了两种语言的交互。另一种Hadoop编程技术Hadoop streaming与Hadoop pipes原理相似,它允许程序员用Python、C++、ruby、VB等各种语言编写mapreduce程序,利用标准输入输出使Java和其他语言实现的程序进行通信。

   


    下面将详细讲述用Hadoop pipes编写第一个wordcount程序的过程以及遇到的各种问题和解决方法:


   1.   参照网上的例子,

   hadoop pipes -D hadoop.pipes.java.recordreader=true -D hadoop.pipes.java.recordwriter=true -input /test.txt(输入文件的路径)-output /output(输出文件的路径) -program /wordcount,这些文件所在路径都必须在hadoop的HDFS目录下,否则会报File does not exist这样的错       误,因为Hadoop不认识HDFS以外的路径。从运行Hadoop pipes 程序的命令可以看出,这个命令最重要的一项就是-program这个选项,这个是指定      C++编写的可执行文件的位置,Hadoop框架会自动的找到这个可执行文件,并利用它来执行mapreduce任务。

   2.怎样生成Linux下基于Hadoop pipes 的wordcount可执行文件,在目录(hadoop-2.4.1-src\hadoop-tools\hadoop-pipes\src\main\native\examples\impl\wordcount-simple.cc,不同版本的Hadoop源码可能在不同的地方存放这个.cc文件)下可以找到Hadoop pipe的wordcount-simple.cc这个源文件。在Hadoop的安装目录的include目录下有wordcount-simple.cc编译成目标文件所需要的.h头文件,在Hadoop安装目录的lib/native目录下有目标文件链接成可执行文件所需要的库文件(libhadooppipes.a libhadooputils.a),

       网上有各种生成可执行文件的做法,但是我都没有试验成功:

(1)http://dongxicheng.org/mapreduce/hadoop-pipes-programming/

ant -Dcompile.c++=yes examples 。

这种方法提示缺少build.xml文件,这可能是ant命令执行需要的文件吧,也不知道该怎么写,所以就放弃了这个方法。


(2)写Linux下的makefile,网上也有很多版本的makefile,比如http://book.51cto.com/art/201211/363814.htm:

HADOOP_INSTALL="你的hadoop安装文件夹" 

PLATFORM=Linux-i386-32(如果是AMD的CPU,请使用Linux-amd64-64)

CC = g++  

CPPFLAGS = -m32 -I$(HADOOP_INSTALL)/c++/$(PLATFORM)/include  

wordcount: wordcount.cpp  

$(CC) $(CPPFLAGS) $< -Wall -g -O2 -o $@ 


将这个文件命名为Makefile放到某个指定目录下,然后在Linux命令窗口输入make命令(或者make -f 指定makefile文件的路径),


结果提示错误。




(3)网上各种方法都无效的情况下,开始自己写makefile文件(取名Makefile),然后make命令执行,期间出现过几种问题:




a. noting to be done for Makefile -》Makefile写的用问题,没有合适的编译规则和生成文件或者是


源文件 没有任何变化编译重复进行不需要重新编译。




b. 找不到Hadoop/Pipes.hh,这种情况是由于没有在编译时没有指定头文件的路径,编译wordcoun-simple.cc应该指定


-I/Hadoop安装路径/include




c. undefined reference to hadoopUtils::split()或者HadoopPipe::runTask(),这些函数都在Pipes.hh、


StringUtils.hh中定义了,但是是 在 libhadooppipes.a和 libhadooputils.a静态库中实现的,链接时需要加上


-L/Hadoop安装路径/lib/native。




d.undefined reference to `HMAC_Final'  ,在链接时加上-lcrypto  选项即可。




如下是我写的Makefile,经测试可以成功生成可执行文件wordcount:




备注:/usr/local/hadoop-2.4.1是Hadoop安装目录




wordcount: wordcount.o
g++ -m64 -o wordcount wordcount.o -L/usr/local/hadoop-2.4.1/lib/native -lhadooppipes -lhadooputils  -lpthread


-lcrypto




wordcount.o: wordcount.cpp 
g++ -c wordcount.cpp -I/usr/local/hadoop-2.4.1/include

clean:
-rm  wordcount.o  wordcount






3.生成wordcount可执行文件后,通过Hadoop fs -put wordcount在Linux文件系统下的路径 Hadoop的HDFS的某个目录 ,将可执行文件


上传到HDFS中,同时也需要将 wordcount的输入文件上传到HDFS中。




4.通过Hadoop pipes命令运行wordcount程序,命令如下:


hadoop pipes -D hadoop.pipes.java.recordreader=true -D hadoop.pipes.java.recordwriter=true 


-D mapred.job.name=wordcount -input /test.txt(HDFS下的输入文件) -output /testPipeOut(HDFS下的输出文件)


-program  /wordcount(HDFS下的可执行程序)




5.在testPipeOut中可以查看程序运行生成的结果文件。