MapReduce分布式计算框架(一)

一、入门

1.简介

背景:
Hadoop设计的目的就是解决海量大文件的处理问题,主要指大数据的存储和计算问题。其中HDFS解决数据存储的问题。MapReduce解决数据计算的问题。MapReduce是hadoop体系下的一种计算模型(计算框架|编程框架)。主要是用来通过代码,对存储在HDFS上的数据进行统计,分析的。
思想:
Hadoop的思想来源于Google的几篇论文,,MapReduce的灵感来源于函数式语言(比如Lisp)中的内置函数map和reduce.map表示对一个列表(List)中的每个元素做计算,reduce表示对一个列表中的每个元素做迭代计算。它们具体的计算是通过传入的函数来实现的,map和reduce提供的是计算的框架。在MapReduce里,Map处理的是原始数据,自然是杂乱无章的,每条数据之间互相没有关系;到了Reduce阶段,数据是以key后面跟着若干个value来组织的,这些value有相关性,至少它们都在一个key下面,于是就符合函数式语言里map和reduce的基本思想了。
实现:
MapReduce将一个大的任务数据,分散在多个服务器中存储(HDFS),结合多个服务器的计算资源,共同完成一个任务的计算程序。采用分而治之的概念,将大的数据拆分为多个小数据(独立的分片split),然后将这些小任务分发下去让多个Map任务并行处理。最后将计算结果 进行合并汇总处理。这样 的话就可以结合多个服务器的计算能力提高任务的执行效率 。
实现过程中的核心概念:
 1.Client
  用户编写的MapReduce程序通过Client提交到JobTracker端 用户可通过Client提供的一些接口查看作业运行状态
 2.JobTracker
  Jobtracker是主线程,它负责接收客户作业提交,调度任务到工作节点上运行,并提供监控工作节点状态及任务进度等管理功能,一个MapReduce集群有一个jobtracker,一般运行在可靠的硬件上。 tasktracker是通过周期性的心跳来通知jobtracker其当前的健康状态,每一次心跳包含了可用的map和reduce任务数目、占用的数目以及运行中的任务详细信息。Jobtracker利用一个线程池来同时处理心跳和客户请求。当一个任务被提交时,组成作业的每一个任务的信息都会存储在内存中,在任务运行的时候,这些任务会伴随着tasktracker的心跳而更新,因此能近乎实时的反映任务进度和健康状况。
 3.TaskTracker
  TaskTracker 会周期性地通过“心跳”将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等) TaskTracker 使用“slot”等量划分本节点上的资源量(CPU、内存等)。一个Task 获取到
  一个slot 后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。slot 分为Map slot 和Reduce slot 两种,分别供MapTask 和Reduce Task 使用
 4.Task
  Task 分为Map Task 和Reduce Task 两种,均由TaskTracker 启动。MapTask:局部计算任务(多个任务+并行执行),ResuceTask:汇总计算任务。Job:一个完整的计算任务,由局部计算任务和汇总计算任务构成。

2.Yarn

概念:
有人说Hadoop=hdfs+yarn 有人说Hadoop=hdfs+mapreduce也有人说Hadoop=hdfs+yarn+maperduce。那么这个yarn是什么是我们首先要清楚的问题 。Yarn-分布式资源调度器。它为MapReuce在运行过程中 提供分配所需要的资源。它可以监控和调度多个 服务器上的计算资源(CPU+内存)。
核心组件:
ResourceManager(主节点 master)负责接收用户提交过来的任务,然后为提交的Job任务分配资源(CPU,内存等)。它也是Yarn集群的管理者,可以监控所有从节点的资源状态信息 。
NodeManager(从节点 slave)负责具体任务(MapTask或ReduceTask)的执行。监控本节点的资源并定期向主节点ResourseManager汇报。在执行是由于需要操作HDFS上的数据,所以NodeManager和 HDFS的DateNode是搭建在一台服务器上的。(这样设计主要有两个原因,1.它在计算时需要使用DataNode的 数据,如果数据也在本地的话 会减去 数据在网络传输的过程,节约时间。2.在搭建HDFS系统的时候DataNode使用的仅仅是服务器的硬盘存储资源。而NodeManager是需要进行计算的调用的是服务器的CPU和内存资源。将它们发那个在一个服务器上也可以很好的利用服务器的资源)
在这里插入图片描述
Yarn实践(伪分布式的安装)
yarn的安装直接基于HDFS上面进行。HDFS的安装步骤在前几篇上可以参考。

  1. 校验HDFS是否正常运行
1.可以输入jps 查看SecondaryNameNode、DataNode、NameNode这三个线程是否正常运行
2.在浏览器输入IP+端口查看。例:192.168.229.1050070
  1. 修改Yarn的配置文件使Yarn生效
//这三个文件均在hadoop安装目录下的etc/hodoop/下
 1. mapred-site.xml
 			//配置yarn框架作为MapReduce的资源调度器。(后续随着时代的发展出现了一些效率更高的框架。以后会更换,现在先主要研究这个最原始的设计思想,就还是用这个框架。以后想换的话直接换这个value就行)
		  <property>
		      <name>mapreduce.framework.name</name>
		      <value>yarn</value>
		  </property>
 2. yarn-site.xml
 		//mapreduce的计算方式
		  <property>
		      <name>yarn.nodemanager.aux-services</name>
		      <value>mapreduce_shuffle</value>
		  </property>
		  //配置resourcemanager的主机ip。如果配置了etc/hossts文件域名映射后可以直接写主机名
		  <property>
		      <name>yarn.resourcemanager.hostname</name>
		      <value>hadoop10</value>
		  </property>

 3. slaves
	  hadoop10 //既是DataNode的ip也是NodeManager的ip。
  1. 启动 Yarn。
start-yarn.sh
  1. 验证
 1. 首先查看进程是否正常启动:jps
 2. 输入ip+端口浏览器访问。例:192.168.229.108088

在这里插入图片描述
在这里插入图片描述

二、MapReduce原理及实现

1、实现原理、流程

  1. 客户端向ResourceManager发出Job任务
  2. ResourceManager接收到请求之后根据自己监控的NodeManager的实施情况,将任务分配给比较空闲(剩余资源比较多)的服务器执行
  3. TextInputFormat 对要处理的文件进行 split逻辑切片,根据split的个数启动相应个数的MapTask线程,然后需要执行这些任务的NodeManager就去读取对应的split文件。
  4. 各个NodeManager拿到自己的split文件之后每次读一行,每读一行就调用一次我们自定义的map方法,最终生成一个自己计算完之后的临时文件。
  5. 在局部计算(MapTask)结束之后就要进行汇总计算(ReduceTask)了。这个汇总计算 也有可能是在刚才进行局部计算的节点上进行(因为他已经结束了自己的局部计算,现在又闲了)。也有可能是在另一台 NodeManager上进行。这个NodeManager会下载刚才所有局部计算结束之后的那个临时文件。然后进行合并,将文件合并之后。随着每一行数据的读取循环调用reduce方法 最终计算出来Job任务需要的最终结果
    具体应用中的实现图
    在这里插入图片描述

2.典型案例WordCount的实现。

案例说明:

  1. 客户端发出来一个Job任务。任务是现在hdfs上有个hello.txt文件。文件中存储的是一些名字。要求统计出每个名字出现的次数。
  2. MapTask 拿到自己的块之后,现将文件一行一行读取,然后统计每个名字出现的次数,然后用一个Map键值对存放自己处理的结果,其中键就是每个名字,值都是1.
  3. Reduce拿到每个MapTask的处理结果之后,进行合并,在合并的时候将它们处理为键值对,键是每个名字,值是一个数组,数组中存储了MapTask记录的每个值。然后在通过自定义的reduce方法计算出每个名字出现的次数。形成一个键值对,键是名字。值是名字一共 出现的次数。即完成Job的任务。

实现流程:

  1. 环境:Windows上的 IDEA,一台伪分布式CentOS7 虚拟机(可以正常打开使用yarn和hdfs)
  2. 在IDEA中创建一个空的maven项目
  3. 在resource中导入hadoop的log4j.properties文件
  4. 在pom文件中加入以下依赖
 	<packaging>jar</packaging>//打包为jar包 。可以上传到linux服务器上运行测试
 	//解决有可能出现的乱码问题
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 	 //导入所需依赖
	<dependency>
	    <groupId>org.apache.hadoop</groupId>
	    <artifactId>hadoop-client</artifactId>
	    <version>2.9.2</version>
	</dependency>
//设置最后打包完之后项目的名字
	<build>
        <finalName>ms</finalName>
    </build>
  1. 新建一个类:main–java–demo–WordCountJob 在里面编写Job作业和实现map、reduce类。注意事项大部分都写在代码的注释里了:
package demo;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;


//这个类首先要继承Configured这个类,然后实现Tool接口
class WordCountJob extends Configured implements Tool {

    //程序执行的入口,主方法。
    public static void main(String[] args) throws Exception {
        //他在底层会调用下面这个run方法,并且返回执行结果0(失败)或者1(成功)
        ToolRunner.run(new WordCountJob(),args);
    }

    //Job任务的主要配置
    public int run(String[] strings) throws Exception {
        //1.创建配置类对象
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS","hdfs://hadoop10:9000");
        //2.创建Job对象
        Job job = Job.getInstance(conf);
        job.setJarByClass(WordCountJob.class);//调用这个方法会在执行主方法的时候使用配置文件去执行
        //3.设置要读取和输出的方式和路径
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);
        FileInputFormat.addInputPath(job,new Path("/hello.txt"));
            //这个文件就是我们要计算的文件。目录路径写成hdfs文件系统的路径在测试前我们需要写一个这样的文件并上传到hdfs的根目录下
        FileOutputFormat.setOutputPath(job,new Path("/out1"));
            //这个路径是我们最终的计算结果需要放在那里的路径。也是在hdfs上的路径。注意点:这个路径在执行前不能存在。
            // 如果存在会报错,(因为目录存在的话它可能以为我以前是不是做过这个计算了)
        //4.设置Mapper和Reduce
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReduce.class);
            //这里的两个类就是下面写的静态内部类
        //5.设置map和reddduce输出的kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //6.提交任务,并且等待执行结果然后返回一个值
        boolean b = job.waitForCompletion(true);
            //首先这个方法的返回值是布尔类型的true或者false表示程序执行完后成功没哟。
        // 里面的这个参数代表的是是否要打印日志信息。
        return b?1:0;//这里使用三目运算符。如果执行成功就返回一个1,执行失败就返回一个0
    }


    //MapTask在局部计算的时候需要将输入的数据进行怎样的操作然后输出怎样的一个kv临时文件供后面的汇总计算使用
    //在这个方法中需要重写map方法去实现局部计算具体的代码(按下ctrl+o 弹出窗口显示可以重写的方法)
    public static class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable>{
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String[] arr=value.toString().split(",");//这里首先拿到输入的数据并且转换为字符喜欢数组中间用逗号分隔
            //然后对这个数组做遍历,将我们计算出的数据写到我们局部计算输出的文件中
            for(String name:arr){
                context.write(new Text(name),new IntWritable(1));
            }
        }
        //这里我们看到这个这个方法需要写入4个参数,他们分别代表的是:
        /*参数1:偏移量
         * 参数2:读取到的每一行的行数据
         * 参数3:执行完这个方法返回的键值对中键的Hadoop类型
         * 参数4:执行完这个方法返回的键值对中值的Hadoop类型
         * */
        //这里涉及到了Java中的常用类型和Hadoop中类型的转换:
        /*首先我们来看一下对应关系:
         * Java      Hadoop
         * int       IntWritable
         * Long      LongWritable
         * String    Text
         * 然后在来看一下转换方式:
         * int--->IntWritable:new IntWritable(1)
         * IntWritable--->int:IntWritable对象.get()
         *
         * String--->Text:new Text("中国")
         * Text--->String:Text对象.toString()*/
    }

    //Reduce在拿到局部计算的结果以后进行怎样的操作计算得出Job任务所需要的最终结果
    //在这个方法中需要重写reduce方法去实现局部计算具体的代码
    public static class WordCountReduce extends Reducer<Text,IntWritable,Text,IntWritable>{
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum=0;//因为我们最终要统计每个名字出现的次数,所以我们定义一个和,然后遍历局部计算的数组,计算出 出现的次数
            for(IntWritable v:values){
                sum+=v.get();
            }
            context.write(key,new IntWritable(sum));
        }
        //在这个方法中我们也看到这个这个方法需要写入4个参数,他们分别代表的是:
        /*参数1:从局部计算结果中拿到的数据的键的Hadoop类型
         * 参数2:从局部计算结果中拿到的数据的值的Hadoop类型
         * 参数3:执行完整个Job作业需要返回的键值对中键的类型
         * 参数4:执行完整个Job作业需要返回的键值对中值的类型
         * */
    }

}

注意:测试前需要将测试的文件上传到hdfs上,并给权限
6.测试验证:

有两种方式:
1.在IDEA的主程序中直接运行
2.使用maven中的package打包之后,将打好的jar包上传到Linux上,然后执行命令运行
	例如:hadoop jar mr.jar demo.WordCountJob
3.执行完毕之后可以在hdfs的/out1下查看计算结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值