假如你有一個上千台的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>
摘自 snnn