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中可以查看程序运行生成的结果文件。