分布式編程模式MapReduce應用

來源:互聯網
上載者:User

Hadoop 是Google MapReduce的一個Java實現。MapReduce是一種簡化的分布式編程模式,讓程式自動分布到一個由普通機器組成的超大叢集上並發執行。就如同java程式員可以不考慮記憶體泄露一樣, MapReduce的run-time系統會解決輸入資料的分布細節,跨越機器叢集的程式執行調度,處理機器的失效,並且管理機器之間的通訊請求。這樣的模式允許程式員可以不需要有什麼並發處理或者分布式系統的經驗,就可以處理超大的分布式系統得資源。

  一、概論

  作為Hadoop程式員,他要做的事情就是:

  1、定義Mapper,處理輸入的Key-Value對,輸出中間結果。

  2、定義Reducer,可選,對中間結果進行規約,輸出最終結果。

  3、定義InputFormat 和OutputFormat,可選,InputFormat將每行輸入檔案的內容轉換為Java類供Mapper函數使用,不定義時預設為String。

  4、定義main函數,在裡面定義一個Job並運行它。

  然後的事情就交給系統了。

  1.基本概念:Hadoop的HDFS實現了google的GFS檔案系統,NameNode作為檔案系統的負責調度運行在master,DataNode運行在每個機器上。同時Hadoop實現了Google的MapReduce,JobTracker作為MapReduce的總調度運行在master,TaskTracker則運行在每個機器上執行Task。

  2.main()函數,建立JobConf,定義Mapper,Reducer,Input/OutputFormat 和輸入輸出檔案目錄,最後把Job提交給JobTracker,等待Job結束。

  3.JobTracker,建立一個InputFormat的執行個體,調用它的getSplits()方法,把輸入目錄的檔案拆分成FileSplist作為Mapper task 的輸入,產生Mapper task加入Queue。

  4.TaskTracker 向 JobTracker索求下一個Map/Reduce。

  Mapper Task先從InputFormat建立RecordReader,迴圈讀入FileSplits的內容產生Key與Value,傳給Mapper函數,處理完後中間結果寫成SequenceFile.

  Reducer Task 從運行Mapper的TaskTracker的Jetty上使用http協議擷取所需的中間內容(33%),Sort/Merge後(66%),執行Reducer函數,最後按照OutputFormat寫入結果目錄。

  TaskTracker 每10秒向JobTracker報告一次運行情況,每完成一個Task10秒後,就會向JobTracker索求下一個Task。

  Nutch項目的全部資料處理都構建在Hadoop之上,詳見Scalable Computing with Hadoop。

  二、程式員編寫的代碼

  我們做一個簡單的分布式的Grep,簡單對輸入檔案進行逐行的正則匹配,如果符合就將該行列印到輸出檔案。因為是簡單的全部輸出,所以我們只要寫Mapper函數,不用寫Reducer函數,也不用定義Input/Output Format。

  package demo.hadoop

  public   class HadoopGrep {

  public   static   class RegMapper extends MapReduceBase implements Mapper {

  private Pattern pattern;

  public   void configure(JobConf job) {

  pattern = Pattern.compile(job.get( " mapred.mapper.regex " ));

  }

  public   void map(WritableComparable key, Writable value, OutputCollector output, Reporter reporter)

  throws IOException {

  String text = ((Text) value).toString();

  Matcher matcher = pattern.matcher(text);

  if (matcher.find()) {

  output.collect(key, value);

  }

  }

  }

  private HadoopGrep () {

  } // singleton

  public   static   void main(String[] args) throws Exception {

  JobConf grepJob =   new JobConf(HadoopGrep. class );

  grepJob.setJobName( " grep-search " );

  grepJob.set( " mapred.mapper.regex " , args[ 2 ]);

  grepJob.setInputPath( new Path(args[ 0 ]));

  grepJob.setOutputPath( new Path(args[ 1 ]));

  grepJob.setMapperClass(RegMapper. class );

  grepJob.setReducerClass(IdentityReducer. class );

  JobClient.runJob(grepJob);

  }

  }

  RegMapper類的configure()函數接受由main函數傳入的尋找字串,map() 函數進行正則匹配,key是行數,value是檔案行的內容,符合的檔案行放入中間結果。

  main()函數定義由命令列參數傳入的輸入輸出目錄和匹配字串,Mapper函數為RegMapper類,Reduce函數是什麼都不做,直接把中間結果輸出到最終結果的的IdentityReducer類,運行Job。

  整個代碼非常簡單,絲毫沒有分布式編程的任何細節。

  三.運行Hadoop程式

  Hadoop這方面的文檔寫得不全面,綜合參考GettingStartedWithHadoop 與Nutch Hadoop Tutorial 兩篇後,再碰了很多釘子才終於完整的跑起來了,記錄如下:

  3.1 local運行模式

  完全不進行任何分散式運算,不動用任何namenode,datanode的做法,適合一開始做調試代碼。

  解壓hadoop,其中conf目錄是配置目錄,hadoop的設定檔在hadoop-default.xml,如果要修改配置,不是直接修改該檔案,而是修改hadoop-site.xml,將該屬性在hadoop-site.xml裡重新賦值。

  hadoop-default.xml的預設配置已經是local運行,不用任何修改,配置目錄裡唯一必須修改的是hadoop-env.sh 裡JAVA_HOME的位置。

  將編譯好的HadoopGrep與RegMapper.class 放入hadoop/build/classes/demo/hadoop/目錄 找一個比較大的log檔案放入一個目錄,然後運行

  hadoop / bin / hadoop demo.hadoop.HadoopGrep log檔案所在目錄 任意的輸出目錄 grep的字串

  查看輸出目錄的結果,查看hadoop/logs/裡的作業記錄。

  在重新運行前,先刪掉輸出目錄。

  3.2 單機叢集運行模式

  現在來搞一下只有單機的叢集.假設以完成3.1中的設定,本機名為hadoopserver

  第1步.    然後修改hadoop-site.xml ,加入如下內容:

  < property >

  < name > fs.default.name

  < value > hadoopserver:9000

  < property >

  < name > mapred.job.tracker

  < value > hadoopserver:9001

  < property >

  < name > dfs.replication

  < value > 1

  從此就將運行從local檔案系統轉向了hadoop的hdfs系統,mapreduce的jobtracker也從local的進程內操作變成了分布式的任務系統,9000,9001兩個連接埠號碼是隨便選擇的兩個空餘連接埠號碼。

  另外,如果你的/tmp目錄不夠大,可能還要修改hadoop.tmp.dir屬性。

  第2步. 增加ssh不輸入密碼即可登陸。

  因為Hadoop需要不用輸入密碼的ssh來進行調度,在不su的狀態下,在自己的home目錄運行ssh-keygen -t rsa ,然後一路斷行符號產生密鑰,再進入.ssh目錄,cp id_rsa.pub authorized_keys

  詳細可以man 一下ssh, 此時執行ssh hadoopserver,不需要輸入任何密碼就能進入了。

  3.格式化namenode,執行

  bin/hadoop namenode -format

  4.啟動Hadoop

  執行hadoop/bin/start-all.sh, 在本機啟動namenode,datanode,jobtracker,tasktracker

  5.現在將待尋找的log檔案放入hdfs,。

  執行hadoop/bin/hadoop dfs 可以看到它所支援的檔案操作指令。

  執行hadoop/bin/hadoop dfs put log檔案所在目錄 in ,則log檔案目錄已放入hdfs的/user/user-name/in 目錄中

  6.現在來執行Grep操作

  hadoop/bin/hadoop demo.hadoop.HadoopGrep in out

  查看hadoop/logs/裡的作業記錄,重新執行前。運行hadoop/bin/hadoop dfs rmr out 刪除out目錄。

  7.運行hadoop/bin/stop-all.sh 結束

  3.3 叢集運行模式

  假設已執行完3.2的配置,假設第2台機器名是hadoopserver2

  1.建立與hadoopserver同樣的執行使用者,將hadoop解壓到相同的目錄。

  2.同樣的修改haoop-env.sh中的JAVA_HOME 及修改與3.2同樣的hadoop-site.xml

  3. 將hadoopserver中的/home/username/.ssh/authorized_keys 複製到hadoopserver2,保證hadoopserver可以無需密碼登陸hadoopserver2

  scp /home/username/.ssh/authorized_keys username@hadoopserver2:/home/username/.ssh/authorized_keys

  4.修改hadoop-server的hadoop/conf/slaves檔案, 增加叢集的節點,將localhost改為

  hadoop-server

  hadoop-server2

  5.在hadoop-server執行hadoop/bin/start-all.sh

  將會在hadoop-server啟動namenode,datanode,jobtracker,tasktracker

  在hadoop-server2啟動datanode 和tasktracker

  6.現在來執行Grep操作

  hadoop/bin/hadoop demo.hadoop.HadoopGrep in out

  重新執行前,運行hadoop/bin/hadoop dfs rmr out 刪除out目錄

  7.運行hadoop/bin/stop-all.sh 結束。

  四、效率

  經測試,Hadoop並不是萬用靈丹,很取決於檔案的大小和數量,處理的複雜度以及群集機器的數量,相連的頻寬,當以上四者並不大時,hadoop優勢並不明顯。

  比如,不用hadoop用java寫的簡單grep函數處理100M的log檔案只要4秒,用了hadoop local的方式運行是14秒,用了hadoop單機叢集的方式是30秒,用雙機叢集10M網口的話更慢,慢到不好意思說出來的地步。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.