MapReduce

MapReduce

HDFS 读操作

 

HDFS 写(文件上传)操作

 

MapReduce:

 

MapReduce的设计目标是可以对一组顺序组织的数据元素/记录进行处理。

MapReduce提供了以下的主要功能:

数据划分和计算任务调度:系统自动将一个作业(Job)待处理的大数据划分为很多个数据块,每个数据块对应于一个计算任务(Task),并自动调度计算节点来处理相应的数据块。作业和任务调度功能主要负责分配和调度计算节点(Map节点或Reduce节点),同时负责监控这些节点的执行状态,并负责Map节点执行的同步控制。

数据/代码互定位:为了减少数据通信,一个基本原则是本地化数据处理,即一个计算节点尽可能处理其本地磁盘上所分布存储的数据,这实现了代码向数据的迁移;当无法进行这种本地化数据处理时,再寻找其他可用节点并将数据从网络上传送给该节点(数据向代码迁移),但将尽可能从数据所在的本地机架上寻 找可用节点以减少通信延迟。

   系统优化:为了减少数据通信开销,中间结果数据进入Reduce节点前会进行一定的合并处理;一个Reduce节点所处理的数据可能会来自多个Map节点,为了避免Reduce计算阶段发生数据相关性,Map节点输出的中间结果需使用一定的策略进行适当的划分处理,保证相关性数据发送到同一个Reduce节点;此外,系统还进行一些计算性能优化处理,如对最慢的计算任务采用多备份执行、选最快完成者作为结果。

出错检测和恢复:以低端商用服务器构成的大规模MapReduce计算集群中,节点硬件(主机、磁盘、内存等)出错和软件出错是常态,因此 MapReduce需要能检测并隔离出错节点,并调度分配新的节点接管出错节点的计算任务。同时,系统还将维护数据存储的可靠性,用多备份冗余存储机制提 高数据存储的可靠性,并能及时检测和恢复出错的数据

原理:

Mr application master 分配和控制maptask

MR中的四个独立实体

  1. 客户端(client): 编写mapreduce程序,配置作业,提交作业,这就是程序员完成的工作。
  2. JobTracker: 初始化作业,分配作业,与TaskTracker通信,协调整个作业的执行。
  3. TaskTracker: 保持与JobTracker的通信,在分配的数据片段上执行Map或Reduce任务,TaskTracker和JobTracker的不同有个很重要的方面,就是在执行任务时候TaskTracker可以有n多个,JobTracker则只会有一个。
  4. Hdfs: 保存作业的数据、配置信息等等,最后的结果也是保存在hdfs上面。

流程角度运作机制详解:

  • 客户端编写好mapreduce程序,配置好mapreduce的作业(也就是job)。
  • 提交job到JobTracker上。
  • JobTracker分配一个新的job任务的ID值;检查输出目录是否存在,如果不存在就抛出错误给客户端;检查输入目录是否存在,如果不存在同样抛出错误;根据输入计算输入分片(Input Split),如果分片计算不出来也会抛出错误。
  • 以上检查都通过,JobTracker就会配置Job需要的资源。
  • JobTracker初始化作业,将Job放入一个内部的队列,让配置好的作业调度器能调度到这个作业。
  • 作业调度器初始化job,创建一个正在运行的job对象(封装任务和记录信息),以便JobTracker跟踪job的状态和进程。
  • 作业调度器获取输入分片信息(input split),每个分片创建一个map任务。
  • tasktracker运行一个简单的循环机制定期发送心跳给jobtracker(间隔五秒,可配置),心跳是jobtracker和tasktracker沟通的桥梁,通过心跳,jobtracker可以监控tasktracker是否存活,也可以获取tasktracker处理的状态和问题,同时tasktracker也可以通过心跳里的返回值获取jobtracker给它的操作指令。
  • 分片执行任务,在任务执行时候jobtracker可以通过心跳机制监控tasktracker的状态和进度,同时也能计算出整个job的状态和进度,而tasktracker也可以本地监控自己的状态和进度。
  • 当jobtracker获得了最后一个完成指定任务的tasktracker操作成功的通知时候,jobtracker会把整个job状态置为成功。
  • 然后当客户端查询job运行状态时候(异步操作),客户端会查到job完成的通知的,任务执行完成。
  • 如果job中途失败,mapreduce也会有相应机制处理,一般而言如果不是程序本身有bug,mapreduce错误处理机制都能保证提交的job能正常完成,如果是程序本身bug,任务在重复执行2~3次后,会结束执行,jobtracker会把整个job状态置为失败。

内置数据类型:

  • BooleanWritable:标准布尔型数值

  • ByteWritable:单字节数值

  • DoubleWritable:双字节数值

  • FloatWritable:浮点数

  • IntWritable:整型数

  • LongWritable:长整型数

  • Text:使用UTF8格式存储的文本

  • NullWritable:当<key, value>中的key或value为空时使用

MapReduce使用:

Map阶段

package com.hadoop.mr;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;
/**
 * 该类是让maptask来调用的
 * @author Administrator
 * 继承了一个父类,里面有四个泛型参数,读数据的公共操作都封装好了,
 * 它会读取数据后传送到这个程序中,以key,value的形式进行数据传递
 * KEYIN:默认情况下,是mr框架所读取到的一行文本的起始偏移量,Long
 * VALUEIN:默认情况下,是mr框架所读的一行文本的内容 类型是String
 * KEYOUT;用户自定义逻辑处理完以后输出的数据中的key :指的是单词  String
 * VALUEOUT:用户自定义逻辑处理完之后输出的数据的value :单词出现的次数 1 Long
 * 无论是KEYIN还是KEYOUT都要经过网络传输,所以必须经过序列化
 * 在hadoop中有一个更精简的序列化接口,Long要写出LongWritable
 * 本质上还是Long,只是实现了hadoop的序列化接口。String序列化成Text
 */
public class WordcountMap extends Mapper<LongWritable, Text, Text,LongWritable >{
  /**
   * 业务逻辑要在该方法中编写,重写map 
   * maptask会对每一行输入数据调用我们自定义的map方法
   * Key:一行的偏移量
   * value:一行的内容
   * 实际业务:将文件内容中一行按照空格切割单词
   * 此时Key没有太大用处,value是一行的内容对我们有用
   */
  @Override
  protected void map(LongWritable key, Text value,Context context)
      throws IOException, InterruptedException {
    //拿到一行内容
    //将maptask传给我们的文本内容现转换为String
    String line = value.toString();
    //根据空格将这一行内容切分成单词
    String[] words = line.split("");
    /**
     * 遍历统计次数
     * 此时有两种思路:1.把统计好一行的单词封装成map("单词","次数")
     * 2.把统计好的一行的任意个单词都将次数写为1,相同的也写成1 
     * 第一种思路是无法完全统计的,因为有好多行,统计起来比较麻烦
     * 第二种思路是,只要出现一次单词就计数为1,等到reduce阶段再去做统计
     * 因为reduce的统计是有范围的,所以一定范围内相同的单词计数为1
     * 再进行叠加即可。相同的单词会到一个文件中去。
     */
    //将单词输出为<单词,1>
    for (String word : words) {
      /**写出单词直接用mr框架提供的上下文对象 随后maptask分发数据的时候是
       * 按照单词分发的,所有key应该是单词,相同的单词会发给相同的reducetask
       */
      context.write(new Text(word), new LongWritable(1));
    }
  }
//  public static void main(String[] args) {
//    String line="asdgag";
//    String[] split = line.split("");
//    System.out.println(split[0]);
//  }
}

Reduce阶段

package com.hadoop.mr;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

/**
 * 该类是让reducetask来调用的,reducetask程序在框架中写好 KEYIN VALUEIN:与mapper输出的KEYOUT
 * VALUEOUT类型对应 所以KEYIN应该是单词,类型Text VALUEIN对应的是输出单词的次数 1 LongWritable(1)
 * KEYOUT,VALUEOUT 是自定义reducer逻辑处理结果的输出类型 那么reduce输出的结果是单词和它的总次数 KEYOUT是单词 类型
 * Text VALUEOUT 是总次数 LongWritable
 */
public class WordcountReduce extends Reducer<Text, LongWritable, Text, LongWritable> {

  /**
   * key:是一组相同单词kv对的key,这个是maptask分发的结果
   * 比如<hello,1><hello,1><hello,1><hello,1>
   * 但是reducetask是有范围的,还有可能是<a,1><a,1><a,1><a,1>
   * reduce为了统计单词的个数,在调用这个方法时应该把相同的单词
   * 作为一组来调用一次
   * key:hello  value:1+1+1+1.....所以第二个参数是迭代器
   * 是用来迭代结果。
   * reducetask就可以统计一个单词的总次数了。
   */
  @Override
  protected void reduce(Text key, Iterable<LongWritable> values, Context context)
      throws IOException, InterruptedException {
    //计数,对单个单词进行合并计数
    Long count=(long) 0;
    for (LongWritable value : values) {
      count+=value.get();
    }
    //将一个单词和它出现的次数写进context
    context.write(key,new LongWritable(count));
  }
}

 Run阶段

package com.hadoop.mr;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

/**
 * 写好的map与reduce程序,需要一个启动的主类
 * 然后打包到每个节点上进行启动
 * 相当于yarn集群的客户端,在此封装相关参数
 * 指定jar包,最后交给yarn分配资源
 * */
public class WordcountDriver {
  public static void main(String[] args) throws Exception {
    //封装成一个job对象(封装了mapreduce的相关参数)
    Configuration cfg = new Configuration();    
    /**
     * cfg不用设置参数的原因 
     * 将mr程序发布到Linux中,Linux中节点都有hadoop配置,
     * 到时会自动读取cfg.set("mapreduce.framwork.name","yarn")....
     */
    //这里导的是org.apache.hadoop.mapreduce.Job;
    //mapred jar包已过时
    Job job = Job.getInstance(cfg);
    //指定本程序的jar包缩在的本地路径
    job.setJarByClass(WordcountDriver.class);
    //指定本业务job使用的mapper业务类
    job.setMapperClass(WordcountMap.class);
    job.setReducerClass(WordcountReduce.class);
    //指明mapper和reduce的输出key/value类型
    //一定要注意Text的类型 apache.hadoop.io.Text
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(LongWritable.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(LongWritable.class);
    //指定job的输入原始文件所在目录
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    //指定job的输出结果所在的目录
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    // job.submit() 提交
    //true代表的是:要把集群返回的信息打印出来看
    //completion:表示集群运行成功还是失败
    boolean completion = job.waitForCompletion(true);
    System.out.println(completion?0:1);
  }
}

在Hadoop上运行

(1)将mapreduce程序打包成jar文件
(2)将打包好的jar文件传到你hadoop集群的机器上(我的hadoop集群是装在linux虚拟机中的)用SSH把jar传过去
(3)创建一个要测试的文件,上传到/wordcount1/input目录中
(4)在HADOOP上运行该MapReduce程序
    hadoop jar hadoop.jar  com.zhiyou.hadoop.mr.WordCountDriver 
   /wordcount1/input   /wordcount1/output      
 hadoop.jar:从eclipse中导出的jar包
 com.zhao.hadoop.mr.WordCountDriver :jar包中的主程序所在的类
/wordcount1/input:输入的文件路径
/wordcount1/output  :输出的文件路径
(5)在/wordcount1/output中查看第二个文件,查看运行结果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值