Hadoop assembly (MR-YARN-HDFS)

MapReduce is a distributed computing program is the core framework Hadoop-based data analysis and calculation of the map is divided into two phases and reduce a total of three processes..:

AppMaster: responsible for the entire process of program scheduling and coordination of state

MapTask: responsible for overall data processing flow map stage

ReduceTask: Reduce responsible for the entire data stream processing stage

Map stage :( responsible for a task into multiple tasks)

Map的编程规范:

1.用户自定义的Mapper继承自己的父类Mapper

2.Mapper的输入数据是KV对的形式(可自定义)

3.Mapper中的业务逻辑写在map方法中

4.Mapper的输出数据是KV对的形式(可自定义)

5.map()方法对每一个<k,v>调用一次

Reduce stage :( responsible for the results of post-processing task decomposition summary)

Reducer:

1.用户自定义Reducer要继承Reducer

2.Reducer的输入类型要对应Mapper的输出类型,也是kv

3.Reducer的业务逻辑写在reduce()方法中

4.ReduceTask进程对每一组相同的<k,v>组调用一次reduce()方法

Driver stage:

相当于yarn集群的客户端,用于提交我们整个程序到yarn集群,提交的是封装了Map Reduce程序相关运行参数的job对象

mapreduce process:

1.对文件进行切片,提前想好块的大小如何分配
2.启动相应数量的 maptask 进程
3.调用 FileInputFormat 中的 RecordReader,读一行数据并封装为 k1v1
4.调用自定义的 map 函数,并将 k1v1 传给 map,一个任务对应一个 map
5.收集 map 的输出,进行分区和排序,这块要注意优化。
6.reduce task 任务启动,并从 map 端拉取数据
7.reduce task 调用自定义的 reduce 函数进行处理
8.调用 outputformat 的 recordwriter 将结果数据输出

Map parallelism decision mechanisms:

Data slice: Is the input slice logically, not cut into pieces which are stored on disk, and

1. Map stage a degree of parallelism determined by the job of job submission client is the number of slices

2. Each slice assigned a split example of parallel processing mapTask

3. By default, the tile size = blockSize

Does not consider the overall data set 4. slices, slice by slice, but a separate file for each

fileInputFormat slicing process:

1.程序先找到你数据存储的目录
2.开始遍历处理目录下的每一个文件
3.遍历第一个文件a.txt,
	a.获取文件大小fs.sizeOf(a.txt)
    b.计算切片大小 
    c.开始切, 形成第一个切片,每次切片时,都要片段剩下的部分是否大于块的1.1倍, 不大于1.1倍的就划为一块 
    d.将切片信息写到一个切片规划中 
    e.整个切片过程在getSplit()方法中完成 
    f. InputSplit只记录切片的元数据信息
4.提交切片文件到yarn上, yarn上的appMaster就可以根据切片文件计算开启mapTask个数

MapReduce Optimization:

主要考虑:数据输入,Map阶段, Reduce阶段、IO传输、数据倾斜问题和常用的调优参数 

数据输入: 设置合并小文件/CombineTextInputFormat作为输入, 解决输入端大量小文件场景

map阶段: 减少溢写(spill)次数, 从而减少磁盘IO; 减少合并(Merge次数), 从而缩短MR处理时间; 在map后, 进行combine处理.

reduce阶段: 合理设置map和reduce数. 太少会导致Task等待, 太多会导致map, reduce任务竞争资源, 造成处理超时等错误; 设置map, reduce共存, 使map运行一定程度后, reduce也开始运行; 规避使用reduce, 因为reduce在用于数据集的时候会产生大量网络消耗; 合理设置reduce的buffer

IO传输: 采用数据压缩和序列化二进制文件 比如snappy

数据倾斜: 1.自定义分区2.combine聚合饼精简数据 3.采用mapJoin, 尽量避免reducejoin

mapReduce of worldCount Programming Case:

pom-dependent file introduced:

<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>2.7.5</version>
        </dependency>

map stage:

package mapreducedemo;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @author Jeady
 * @Date 2020/02/07
 */
//自定义Mapper, 继承Mapper
public class WorldCount extends Mapper<LongWritable, Text,Text,LongWritable> {

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

        String[] split = value.toString().split(",");
        for (String s : split) {
            context.write(new Text(s.getBytes()),new LongWritable(1));
        }
    }
}

reduce stage:

package mapreducedemo;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @author Jeady
 * @Date 2020/02/07
 */
//自定义reducer
public class WorldCountReducer extends Reducer<Text, LongWritable,Text,LongWritable> {
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {

        long count = 0;
        for (LongWritable value : values) {
            count += value.get();
        }
        context.write(key,new LongWritable(count));
    }
}

main method to test:

package mapreducedemo;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

/**
 * @author Jeady
 * @Date 2020/02/07
 */
public class WorldMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //获取job实例
        Job job = Job.getInstance(super.getConf(), WorldMain.class.getSimpleName());

        //设置输入路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job,new Path("hdfs://node01:8020/worldcount"));

        //设置map类
        job.setMapperClass(WorldCount.class);
        job.setMapOutputKeyClass(LongWritable.class);
        job.setMapOutputValueClass(Text.class);

        //设置reduce类
        job.setReducerClass(WorldCountReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        //设置输出路径
        job.setOutputFormatClass(TextOutputFormat.class);
        Path path = new Path("hdfs://node01/world_out");
        TextOutputFormat.setOutputPath(job,path);

        //提交job
        boolean b = job.waitForCompletion(true);
        return b?0:1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();

        WorldMain worldMain = new WorldMain();
        ToolRunner.run(configuration,worldMain,args);
    }
}

Three yarn scheduler:

With the FIFO scheduler (the default): order of submission, sequentially executed

capacity-scheduler The scheduler Capacity: cluster composed by a number of queue scheduling according to the FIFO manner inside each queue, the job

fair-scheduler fair scheduler: Fair scheduler will work to customize the minimum capacity pool according to the task map and reduce the number of slots, and adjust system resources for the job dynamic of all running to support preemption

yarn scheduling process:

1.有YarnClient提交program信息打拼ResourceManager,包括(应用代码和应用需要的一切参数和环境信息)
2.ResourceManager收到请求之后,调用ApplicationMasterManager向NodeManager发送请求,申请一个资源(Container),并且要求Container启动ApplicationMaster.
3.ApplicationMaster启动之后,首先注册自己到ResourceManager,然后为自己的Task申请Container,这个过程是轮训的,循环申请资源,ResourceManager收到请求之后,会要求NodeManager分配资源
4.资源分配完毕之后,Application Master发送请求到NodeManager,启动任务。
5.NodeManager设置Container的运行时环境(jar包,环境变量,任务启动脚本),NodeManager会通过脚本启动任务
6.启动的过程是由NodeManager的ContainerLauncher负责的,ContainerLauncher完成启动任务的工作
7.这一步是在作业执行过程中持续发生的,我用虚线代表,主要包括两类交互,第一,task和Application
Master的交互,task会向AM汇报任务状态和进度信息,比如任务启动,停止,状态更新。ApplicaitonMaster利用这些信息监控task整个执行过程。第二,是NodeManager和ResourceManager的交互,这个过程和任务没有关系,主要是两者之间保持的心跳信息(状态的变化等等)
8.Application Master在检测到作业运行完毕之后,Application Master想Resource Manager
删除自己,并且停止自己执行。

hdfs writing process:

1.客户端向NameNode发出写文件请求。
2.nameNode检查是否已存在文件、检查权限。若通过检查,直接先将操作写入EditLog,并返回输出流对象。(注:WAL,write ahead log,先写Log,再写内存,因为EditLog记录的是最新的HDFS客户端执行所有的写操作。如果后续真实写操作失败了,由于在真实写操作之前,操作就被写入EditLog中了,故EditLog中仍会有记录,我们不用担心后续client读不到相应的数据块,因为在第5步中DataNode收到块后会有一返回确认信息,若没写成功,发送端没收到确认信息,会一直重试,直到成功)
3.client端接收到nameNode的消息, 按128MB的块切分文件。
4.client将NameNode返回的分配的可写的DataNode列表和Data数据一同发送给最近的第一个DataNode节点,此后client端和NameNode分配的多个DataNode构成pipeline管道,client端向输出流对象中写数据。client每向第一个DataNode写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode。(注:并不是写好一个块或一整个文件后才向后分发)
5.每个DataNode写完一个块后,会返回确认信息。
(注:并不是每写完一个packet后就返回确认信息,个人觉得因为packet中的每个chunk都携带校验信息,没必要每写一个就汇报一下,这样效率太慢。正确的做法是写完一个block块后,对校验信息进行汇总分析,就能得出是否有块写错的情况发生)
6.写完数据,关闭输输出流。
7.发送完成信号给NameNode。
(注:发送完成信号的时机取决于集群是强一致性还是最终一致性,强一致性则需要所有DataNode写完后才向NameNode汇报。最终一致性则其中任意一个DataNode写完后就能单独向NameNode汇报,HDFS一般情况下都是强调强一致性)

hdfs reading process:

1.client访问NameNode发出查询请求,
2.nameNode查询元数据信息,获得这个文件的数据块位置列表,返回输入流对象。
3.client就近挑选一台datanode服务器,请求建立输入流 。
4.DataNode向输入流中中写数据,以packet为单位来校验。
5.关闭输入流, client接收数据
Published 20 original articles · won praise 4 · Views 2721

Guess you like

Origin blog.csdn.net/qq_43149023/article/details/104214879