mapReduce

有一段时间没有写了,最近写MapReduce遇见一些问题,总结一下;图片来源网络借鉴

首先看一下YARN的调度流程:
mapReduce_第1张图片

首先各个NodeManager会向ResourceManager反馈自己的资源使用情况

  1. client向ResourceManager提交一个任务,然后根据各个NodeManger的资源使用情况来选择一个节点创建App Mster
  2. NodeManager在提交任务的时候也会拉回ResourceManager分配给自己的Container,这个时候会创建App Mstr
  3. App mstr首先向ResourceManager注册
  4. App mstr 采用轮询的方式通过RPC协议向ResourceManager申请和领取资源
  5. 如果App mstr申请资源成功,则在对于的节点上创建任务
  6. NodeManager准备好运行环境后, 将任务启动命令写到脚本中,并通过运行该脚本启动任务
  7. 各个节点通过RPC协议向APP mstr反馈任务的运行情况
  8. 全部任务运行结束后, APP mstr 向ResourceManager申请注销并关闭自己
    mapReduce_第2张图片

然后说一下MapReduce的执行流程,看图:!mapReduce1](C:\Users\majun\Desktop\study\mapReduce1.png)
mapReduce_第3张图片

  1. 首先从hdfs中读取文件
  2. 切片,默认切片数量为文件切块数量,一个切片对应一个map
  3. 准备读取记录器,每次读取除第一个切片都会跳过第一行,因为切片的原因,第一行的数据并不一定完整
  4. Map计算
  5. partition 计算
  6. 内存排序(真实排序),默认在内存中有100M的数据缓存,每当数据达到80%后会进行一次排序,然后将部分排序后的数据写到本地磁盘,记住这里不是写道hdfs,当map计算完成后会对这些写入到本地磁盘和内存中的数据进行规避,然后等待reduce拉取
  7. combine 计算,数据优化,举例:就像wordcount中, 如果在一个结果中有1G的数据全是相同的单词, 那么就可以提前做统计,这样在shuffle过程中,拉取的数据量会小很多,同时速度也会提高很多,reduce计算的速度也会提升很多
  8. gourp sort 组排序(并非正真意义上的排序), reduce将自己需要的数据拉取回来后做归并
  9. reduce 计算
  10. 结果输出到hdfs
    mapReduce_第4张图片

shuffle:
简单理解可以说是map输出到reduce拉取数据完成的这个过程叫做shuffle,当然这个过程是相当复杂的,也是mapReduce计算优化最多的地方,很多时候map计算输出的结果并不是在当前节点上运行reduce,这个时候就需要进行网络传输, 那么我们就需要尽量压缩map的输出以减少网传输,同时不影响最终结果

样例:计算每个通过同一个地方最快车速的两辆车

输入样例:


输出样例:

2018-09-18 13:01:30-A-00OW-->99.0441265602245693
2018-09-18 13:01:30-A-00OC-->3.0441265602245693
2015-08-22 04:40:58-A-00CX-->119.90590346078514
2014-02-23 04:40:37-A-00LC-->6.663067610118922
2012-11-04 05:40:43-A-00JX-->75.52516524693405
2009-11-16 14:03:18-A-00LC-->123.87260759657283
2007-11-24 12:11:15-A-00EX-->11.10648242892176
2001-03-25 21:33:25-A-00HC-->32.01957317397386
2000-06-08 11:29:23-A-00GC-->116.26392212549797
1997-06-02 20:25:06-A-00AX-->136.6234481822316
1994-10-25 22:11:17-A-00EX-->49.22121124525041
1994-10-25 22:11:17-A-00EB-->40.22121124525041
1992-04-30 13:37:29-A-00OX-->109.88877569550768
1990-02-21 03:50:35-A-00EC-->16.518780915240217

代码:

https://gitee.com/mjlfto/hadoop_mapreduce/blob/master/src/main/java/com/mjlf/mr/speed

结构:
mapReduce_第5张图片

client:

//重写了partition,combine, sort, groupsort

public class SpeedClient {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        //配置实例化
        Configuration conf = new Configuration(true);

        //job实例化
        Job job = Job.getInstance(conf, "speed");

        //设置jar
        job.setJarByClass(SpeedClient.class);

        //设置输入输出
        FileInputFormat.addInputPath(job, new Path("/input/speed.txt"));
        Path outPath = new Path("/speed");
        if (outPath.getFileSystem(conf).exists(outPath)) {
            outPath.getFileSystem(conf).delete(outPath, true);
        }
        FileOutputFormat.setOutputPath(job, outPath);

        //设置map
        job.setMapperClass(SpeedMap.class);
        job.setMapOutputKeyClass(Speed.class);
        job.setMapOutputValueClass(Text.class);


        //设置partitioner
        job.setPartitionerClass(SpeedParation.class);

        //设置sort
        job.setSortComparatorClass(SpeedComparator.class);

        //设置group sort
        job.setGroupingComparatorClass(SpeedGroupComparator.class);

        //设置combiner
        job.setCombinerClass(SpeedCombiner.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);

        //设置reduce
        job.setReducerClass(SpeedReduce.class);

        job.setCombinerKeyGroupingComparatorClass(SpeedGroupComparator.class);

        job.waitForCompletion(true);
    }
}

容易出现的异常:

1.类型异常

​```
 java.io.IOException: wrong key class: class org.apache.hadoop.io.Text is not class com.mjlf.mr.speed.Speed
 类型异常,需要保证map输出是reduce的输入,但是, 如果复写了Combiner,务必小心,这个时候Map的输出是Combiner的输入,Combiner的输出才是Reduce的输入
​```



2.数据读写异常:

​```
Caused by: java.io.EOFException
   at java.io.DataInputStream.readFully(DataInputStream.java:197)
   at java.io.DataInputStream.readUTF(DataInputStream.java:609)
   at java.io.DataInputStream.readUTF(DataInputStream.java:564)
   at com.mjlf.mr.speed.Speed.readFields(Speed.java:69)
   at org.apache.hadoop.io.WritableComparator.compare(WritableComparator.java:158)
   
这个异常会给一个很坑的提示, 就是抛出异常的点在Speed.java:69,这个地方的实现为:
    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.time = dataInput.readUTF();
        this.carN = dataInput.readUTF();
        this.speedNum = dataInput.readDouble();
    }
但是, 这个异常和该方法的实现没有关系
错误原因:
我们重新定义的map输出的排序规则,但是这个地方要求排序只能对map输出的key进行排序, 也就是我们的Speed类必须是Map输出的key
排序实现:
public class SpeedComparator extends WritableComparator {

    public SpeedComparator() {
        super(Speed.class, true);
    }

    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        int result = 0;

        Speed s1 = (Speed) a;
        Speed s2 = (Speed) b;

        try {
            Date d1 = DateFormat.parse(s1.getTime(), "yyyy-MM-dd");
            Date d2 = DateFormat.parse(s2.getTime(), "yyyy-MM-dd");

            if (d1.equals(d2)) {
                return -Double.compare(s1.getSpeedNum(), s2.getSpeedNum());
            } else {
                if (d1.before(d2)) {
                    result = 1;
                } else {
                    result = -1;
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
}
​```

你可能感兴趣的:(java基础,mapreduce,hadoop)