1. 程式人生 > >Eclipse中執行Hadoop程式的各種問題

Eclipse中執行Hadoop程式的各種問題

     搭建了一個Hadoop叢集(一個master,三個slave),參照Hadoop實戰上的wordcount程式碼,在eclipse執行,但是在web頁面上查不到該job的id,後來發現是在單機上執行,那搭建這個叢集還有什麼意義,於是在網上查詢答案,試著在eclipse中將hadoop程式在叢集中跑起來。卻發現其中問題不少啊。

     1.如何使eclipse中的hadoop程式在叢集而不是單機上執行

      通過原始碼,首先是建立一個configuration物件,並且對引數進行解析,接著提交作業所用的Job物件,設定作業jar包,對應的Mapper類和Reducer類,輸入輸出的Key和Value的類及作業的輸入和輸出路徑,最後就是提交作業並等待作業結束。

String tracker = conf.get("mapred.job.tracker", "local");
    if ("local".equals(tracker)) {
      this.jobSubmitClient = new LocalJobRunner(conf);
    } else {
      this.jobSubmitClient = createRPCProxy(JobTracker.getAddress(conf), conf);
    }  


發現原來跟conf資料夾中mapred-site.xml中mapred.job.tracker的屬性是否設定有關,在eclipse之前都沒將配置檔案新增進來,怪不得在Local執行,後來想想也是,你的配置檔案都沒新增進來,都找不到JobTracker和TaskTracker的位置,怎麼可能在叢集執行呢······解決這個問題很簡單,只需要將hadoop中已經配置好的conf資料夾考到當前工程,並新增到工程的build path中,這樣就能在叢集上運行了!(這同時也解釋了在命令列為什麼就不是在單機上運行了,因為conf中的配置檔案是已經新增到路徑中去了的)

  2.Map函式無法找到

做完第一步後,以為可以運行了,卻發現提示java.lang.RuntimeException: java.lang.ClassNotFoundException: Job$Mapper. 

看了下編譯後的檔案,發現Map和Reduce內部類已經編譯好了啊,為什麼會找不到啊,果斷把提示的錯誤複製,百度,發現是Job.setJarByClass(xxx.class)設定jar沒有成功,將網上答案抄了下來

在eclipse執行,使用了WordCount.class的類載入器來尋找包含該類的Jar包,然後設定該Jar包為作業所用的Jar包。但是我們的作業 Jar包是在程式執行時才打包的,而WordCount.class的類載入器是AppClassLoader,執行後我們無法改變它的搜尋路徑,所以使用setJarByClass是無法設定作業Jar包的。我們必須使用JobConf裡的setJar來直接設定作業Jar包。就是新增下面這一句

                                                       ((JobConf)job.getConfiguration()).setJar(jarFile);

其中的jarFile是你已經打包好了的,輸入該jar包的路徑就OK(在命令列中完全省略這一步,直接job.setJarByClass就好了)

3.如何打包

上文提到,需要自己打包,當你的程式碼中沒有用到第三方的jar包的時候,這時是相當輕鬆的,使用eclipse的export,無論打成普通的jar包還是runnable jar都是沒有問題的。但是當時我的應用中是用到了第三方的jar包的,由於hadoop需要將該jar包分發到tasktracker執行,而tasktracker主機肯定是沒有下載第三方jar包的。於是我想到了打成一個runnable jar,裡面包含我所需要的第三方jar包。我使用該jar包中的類是在Map函式中,Map函式肯定是在Tasktracker執行,但是執行時提示始終找不到該類,我明明是加進去了的啊,我猜想是不是打包格式不對啊,煩!百度之,找關於hadoop如何分發本機jar包,果不其然,兩種解決方案

1.將第三方的jar包所有的class與我們自己程式碼打包在一起。這其實很容易做到,使用eclipse的export功能打包成runnable jar,然後選第一項就可以了。

2.建立一個lib目錄,把所依賴的jar包放到該目錄,再和程式碼一起打包。

4.在命令列如何執行有層次的jar包

比如我的主類是Wordcount,但是該類是在包word下,那麼執行在eclipse底下是沒任何問題的,但是當打包以後,卻發現不能執行。網上找答案,發現無一例外都是要執行下面的命令Hadoop jar xxx.jar word.Wordcount input output 

但是還是不行,最後發現當打包runnable的第一種方式,即第三方的jar包所有的class與我們自己程式碼打包在一起,並設定好主類就可以了(在MAINFEST中進行設定)。 這時候的命令為 Hadoop jar xxx.jar input output(不需要設定主函式,因為在打包時候已經設定好了)

總結下,上面幾個看似很簡單的問題花費了我幾天時間,但想想問題出現在:

1.對打包方式不熟悉

2.沒有深刻理解hadoop的內部機制

才會出現上述問題

 另外,分享打包語句

 jar cvfm xxx.jar manifest -C 資料夾/ .  -m 是用自己的mainfest(Main-Class)