向hadoop提交C++程序

假如你有一个上千台的hadoop集群,那你肯定无法保证所有的机器都具有完全一样的操作系统版本。前文已经讲了如何让C/C++程序一次编译,在不同的Linux版本下运行。这里具体讲讲hadoop下的情况。

要想在hadoop上运行C++程序,有两个接口,一个是老的hadoop streaming,不推荐使用。另外一个就是比较新的,hadoop pipes。

一、分发动态链接库文件

Hadoop提供了一个叫DistributedCache的东西,用来给map/reduce任务分发jar和动态链接库(以及其它的只读文件)。launch_container.sh在启动container的时候,一定会把当前工作目录加入到java.library.path和LD_LIBRARY_PATH中。那么怎么把文件扔到DistributedCache中呢?有两种办法。

1.提交任务的时候,加上-files参数,然后填以逗号分割的本机的Unix路径。

2.手动把文件复制到hdfs中,然后在任务的配置中加上mapred.cache.files属性,里面填以逗号分割的hdfs URL。

这两个方法可以混用。

但是此时有个问题,如果机器的数量特别多,任务启动的时候大家一起来找同一个机器要某个文件,那么就会堵住。好在hadoop一般会把一个文件存3份,如果机器数量特别多,那么就需要对这些so文件增大存的份数。

二、设置ELF解释器

但是就算把所有的第三方库的so都提交上去了,某些so必须要求特定版本的glibc才能工作。而libc.so的版本又必须和ld.so的版本匹配。所以,有两个办法

  1. 在链接的时候加上–dynamic-linker ./ld-linux-x86-64.so.2

  2. 在任务的配置中把mapreduce.pipes.executable.interpretor设置成”./ld-linux-x86-64.so.2 ”

三、分发数据文件

然后呢,你会发现光有so文件还不够,有些so文件还需要依赖于很多数据文件,而这些数据文件在目标机器上未必有。例如,ubuntu的glibc,在执行iconv_open函数的时候,需要去/usr/lib/x86_64-linux-gnu/gconv目录下读gconv的数据文件,而对于CentOS,则是在/usr/lib64/gconv目录下。还好有一个很重要的环境变量:GCONV_PATH,可以用来设置这个目录在哪,并且GCONV_PATH的值可以是相对路径,不必是绝对路径。所以结合前面说的,把gconv这整个目录DistributedCache分发即可。

至于环境变量,是这样的:子进程默认会继承父进程的全部环境变量。所以,虽然我们无法设置这个C++程序的环境变量,但是我们设置它的父进程(jvm)的环境变量。示例如下:

<property>
  <name>mapreduce.map.env</name>
  <value>GLOG_log_dir=/tmp/glog,GCONV_PATH=gconv</value>
</property>

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥