Hadoop學習之YARN及MapReduce

weixin_34185560發表於2018-01-24

YARN

YARN是Hadoop的一個資源排程框架,下面簡單介紹下它的執行流程

7789466-490388659c486141.jpg
yarn執行流程.jpg

以上是YARN的一個流程圖,簡單介紹

  1. Client提交任務執行請求
  2. ResourceManager接收到執行請求後,向Client返回一個作業ID,ResourceManager選擇一個NodeManager分配一個Container,此NodeManager啟動一個ApplicationMaster(AM)
  3. AM計算需要的資源及資料,向ResourceManager註冊並申請計算所需要的資源
  4. ResourceManager分配合適的NodeManager給ApplicationMaster,ApplicationMaster與NodeManager協調分配container,啟動相應的Task
  5. Application監控任務的執行情況並與Client通訊,報告程式執行狀態(作業執行失敗,重新執行/在其他節點執行)
  6. 程式結束,相關Container及ApplicationMaster釋放

MapReduce

MapReduce簡介

  • MapReduce是一個分散式的批處理計算框架,源於Google在2014年12月釋出的一篇關於分散式計算的論文,Google並未開源,MapReduce是根據論文思路開發的一套框架,可以說是Google MapReduce的克隆版
  • 一個MapReduce程式分為Map階段和Reduce階段
  • MapReduce的典型特性包括:易於程式設計(使用者只需要在Map和Reduce的實現函式中編寫業務邏輯,就可以實現分散式計算)、擴充套件性好(可根據資源靈活的執行及配置任務)、容錯性高(叢集中一個節點故障,該節點的任務會排程到其他節點執行)、適合海量資料的離線處理

MapReduce應用場景

  • 資料統計,如網站PV、UV統計
  • 搜尋引擎的索引,比如百度就是用MapReduce來建立索引,MapReduce產生的需求背景就是Google建立搜尋索引
  • 海量資料查詢
  • 複雜的資料分析演算法的實現比如聚類演算法、分類演算法、推薦演算法等

MapReduce的短板

  • 實時計算,實時計算講究時效性,MapReduce適合大規模資料的計算,在時效性方面就
  • 流式計算,流式計算的輸入資料是動態的,MapReduce的資料集是靜態的,因而無法實現流式計算
  • DAG計算,DAG計算講究多次迭代,多個作業之間存在很嚴重的依賴關係

MapReduce程式設計模型

分為Map和Reduce階段兩部分組成

Map階段

Map階段由若干Map Task組成

  • 從HDFS獲取輸入資料並解析 InputFormat
  • 資料處理 Mapper
  • 資料分組:Partitioner

Reduce階段

由若干Reduce Task組成,輸入為Map Task的輸出

  • 由Map的輸出資料遠端拷貝
  • 資料按照 key排序
  • 資料處理 Reducer
  • 資料輸出:OutputFormat

內部邏輯

以下為MapReduce簡要的處理過程圖


7789466-6dd3abf9012f9bff.jpg
mapreduce內部邏輯.jpg
  1. 對輸入資料進行分片(Split),一般以預設的block進行split,也可以自定義
  • 檔案分片的過程中,很大可能會出現跨行問題,MapReduce的解決方案是讀取完整,跨block分到上一個split,下一split分這些
  • 在Split的時候,會將資料解析成key-value對,該預設實現為TextInputFormat,Key為行在文字中的偏移量,Value為行內容,如果一行被截斷,則讀取下一個的block的前幾個字元,Split大小也可以自定義
  1. Mapper程式讀取切分好的資料(通過InputFormat介面)
  2. Mapper程式對資料進行處理,按照key、value的形式進行整合
  3. Partitioner對Mapper輸出的資料進行分割槽,決定由哪個Reduce進行處理
  • Partitioner的預設實現為HashPartitioner,具體做法大致是對key取Hash值,相對Reduce的數量取餘,產生的數字即為Reduce Task號
  • Partitioner也允許自定義分割槽
  1. 對資料進行Shuffle和Sort,分配到對應的Reducer進行處理
  2. 結果輸出

程式設計介面

Java程式設計介面

  • 舊API:org.apache.hadoop.mapred,目前不建議使用
  • 新:org.apache.hadoop.mapreduce
  • 新API具有更好的擴充套件性,兩種API內部執行引擎一樣

WordCount

WordCount相當於普通程式語言的HelloWorld

需求:統計規律切分的大規模文字中單詞出現次數

文字中單詞例子:

hello   world   this    my
hh  dd  mm  dd  kk
思路:
  1. Map階段每行資料按分隔符切分,單詞作為key,1為value
  2. Reduce階段:遠端從Map階段的輸出結果copy資料,並進行整理排序,把相同的key合併,形成key對應一組value的資料集,即為reduce的輸入,reduce針對每個key呼叫reduce方法,對value求和
程式設計:
  1. 程式設計採用Java進行,使用maven管理jar包,具體環境設定在以後有機會補充,目前請網上檢視,資料也不少。需要注意的是由於眾所周知的原因,請設定國內maven倉庫映象
    pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.nanri</groupId>
    <artifactId>bigdatalearn</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-common</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
            <version>2.7.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <executions>
                    <execution>
                        <id>default-compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <encoding>UTF-8</encoding>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

程式碼:具體見程式碼註釋

package com.nanri.mapr01;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class WordCountApp {
//map階段,輸入key、value輸出key、value型別
    static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            //讀取資料,將資料轉換成字串
            String line = value.toString();
            //拆分資料
            String[] words = line.split("\t");
            for(String word : words) {
                //輸出需要序列化寫出
                context.write(new Text(word), new IntWritable(1));
            }
        }
    }

    static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        // 輸入:k:v1, v2, v3
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        //定義一個計數器
            int count = 0;
            //遍歷,將key出現的次數累加
            for(IntWritable value : values) {
                count += value.get();
            }
            context.write(key, new IntWritable(count));
        }
    }

//執行程式
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    //定義的job名稱
        String jobName = args[0];
        //輸入路徑
        String inputPath = args[1];
        //輸出路徑,執行時此路徑在hadoop上必須不存在
        String outputPath = args[2];
        //執行配置
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        // 設定作業名稱
        job.setJobName(jobName);
        //設定具體執行類
        job.setJarByClass(WordCountApp.class);
        //mapper和reducer
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        //設定mapper階段的輸出的key和value型別
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //設定reducer階段的key和value型別
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //設定輸入和輸出路徑
        FileInputFormat.setInputPaths(job, new Path(inputPath));
        FileOutputFormat.setOutputPath(job, new Path(outputPath));

        // 作業完成退出
        System.exit(job.waitForCompletion(true)?0:1);
    }
}


程式碼編寫完成後,進行打包,將編譯好的工程jar包檔案上傳到伺服器,執行hadoop jar bigdatalearn-1.0-SNAPSHOT.jar com.nanri.mapr01.WordCountApp wordcountapp /wordcount/input /wordcount/output,jar包後第一個引數為入口類所在的完整路徑,之後引數為具體main方法中定義的引數,需確保輸出路徑不存在,稍等一會,即可看到給的跟蹤地址及執行成功後的提示

  • Mapreduce使用者編寫的程式分為三個部分:Mapper、Reducer、Driver
  • Mapper的輸入資料是K-V對的形式,key一般為行號,value為每行資料
  • Mapper的輸入資料是K-V對的形式,
  • Mapper的業務邏輯寫在map()方法中
  • map()方法對每個<K,V>執行一次
  • Reducer的輸入資料型別對應Mapper的輸出資料型別,也是K-V對
  • Reducetask程式對每一組相同k的<k,v>組呼叫一次reduce()方法
  • 使用者自定義的Mapper和Reducer都要繼承各自的父類
  • 整個程式需要一個Driver來提交,提交的是一個描述了各種必要資訊的job物件

相關文章