大数据—Hadoop之MapReduce流程(二)

一、Combiner

   为什么需要进行Map规范操作?①网络带宽严重被占降低程序效率②单一节点承载过重降低程序性能。为了解决两个问题,在MapReduce编程模型中,在Mapper和Reducer之间有一个非常重要的组件——Combiner。

     ①与Mapper和Reduce不同的是,Combiner没有默认的实现,需要显式的设置在conf中才有作用。②并不是所有的job都使用Conbiner,只有操作满足结合律的才可以设置Combiner。

     每一个Map都可能会产生大量的本地输出,Combiner的作用就是对Map端口的输出先做一次合并,以减少在Map和Reduce节点之间的数据传输量,以提高网络IO性能。Combiner功能:①Combiner实现本地key的聚合,对Map输出的Key排序value进行迭代。②Combiner还有本地Reduce功能。

    小结:在实际的Hadoop集群操作中,是由多台主机一起进行MapReduce的,如果加入规范操作,每一台主机会在Reduce之前进行一次对本机数据的规约,然后在通过集群进行Reduce操作,这样就会大大节省Reduce的时间,从而加快MapReduce的处理速度。

二、Partitioner

 

   MapReduce的使用者通常会指定Reduce任务和Reduce任务输出文件的数量。用户在中间Key上使用分区函数来对数据进行分区,之后在输入到后续任务执行进程。一个默认的分区函数式使用hash方法(比如常见的:hash(key)mod R)进行分区。hash方法能够产生非常平衡的分区。HashPartitioner 对分区的处理过程也就是一个 hash 函数的事,hash 的好处是可以很 key 的分布更加随机。可是,hash 处理也有一个比较突出的问题,那就是某一个分区中可能会包含了很多不同的 key。原因就是因为这里需要对 numReduceTasks 进行取余(取余是必须的,因为 getPartition() 方法的返回值不可以大于 numReduceTasks ),所以 hashCode 相差再大也是于事无补。为了解决这种问题我们可以使用自定制的Partitioner。

   例如:

 public static class LiuPartitioner extends Partitioner<Text, KpiWritable> {
        @Override
        public int getPartition(Text key, KpiWritable value, int numPartitions) {
            // 实现不同的长度不同的号码分配到不同的reduce task中
            int numLength = key.toString().length();

            if (numLength == 11) return 0;
            else   return 1; 
        }
    }

    

//设置为打包运行,设置Partitioner为LiuPartitioner设置ReducerTask的个数为2
//注意:分区的例子必须要设置为打成jar包运行!
    public int run(String[] args) throws Exception {
 
        // 定义一个作业
        Job job = new Job(getConf(), "MyJob");
        // 分区需要设置为打包运行
        job.setJarByClass(MyLiuJob.class);
        // 设置输入目录
        FileInputFormat.setInputPaths(job, new Path(INPUT_PATH));
        // 设置自定义Mapper类
        job.setMapperClass(MyMapper.class);
        // 指定<k2,v2>的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(KpiWritable.class);
        // 设置Partitioner
        job.setPartitionerClass(LiuPartitioner.class);
        job.setNumReduceTasks(2);
         // 设置自定义Reducer类
        job.setReducerClass(MyReducer.class);
        // 指定<k3,v3>的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputKeyClass(KpiWritable.class);
        // 设置输出目录
        FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));
        // 提交作业
        System.exit(job.waitForCompletion(true) ? 0 : 1);
        return 0;
    }

   Partitioner分区主要用于一下两种情况:①根据业务需要,产生多个输出文件。②多个Reduce任务并发运行,提高整体Job的运行效率。
三、Shuffle过程

 

    针对多个Map任务的输出按照不同的分区(Partition)通过网络复制到不同的Reduce任务节点上,这个过程就称为Shuffle。

     

    Shuffle过程:1.Map端:①在Map端首先是InputSplit,在InputSplit中含有DataNode中的数据,每个InputSplit都会分配一个Mapper任务,Mapper任务结束后产生<K2,V2>的输出,这些输出先存放在缓存中,每个Map有一个环形内存缓冲区,用于存储任务的输出。默认大小100MB(io.sort.mb属性),一旦达到阈值0.8(io.sort.spill.percent),一个后台线程就把内容写到(spill)Linux本地磁盘的制定目录(mapred.local.dir)下的新建的一个溢出写文件。②写磁盘前,要进行Partition、sort和combine等操作。通过分区,将不同类型的数据分开处理,之后对不同分区的数据进行排序,如果有Combiner,还要对排序后的数据进行Combine。等最后记录写完,将全部溢出文件合并为一个分区且排序的文件。③最后将磁盘中的数据送到Reduce中,下图Map输出有三个分区,有一个分区数据被送到图示的Reduce任务中,剩下的两个分区被送到其他Reduce任务中。而图示的Reduce任务的其他的三个输入则来自其他节点的Map输出。

     2.Reduce阶段。①Copy阶段:Reduce通过Http方式得到输出文件的分区。Reduce端可能从n个Map的结果中获取数据,而这些Map的执行速度不尽相同,当其中一个Map运行结束时,Reduce就会从JobTracker中获取该信息。Map运行结束后TaskTracker就会得到消息,从而将消息汇报给JobTracker,Reduce定时从JobTracker获取该信息,Reduce端默认有5个数据复制线程从Map端复制数据。②Merge阶段:如果行程多个磁盘文件会进行合并。从Map端复制来的数据首先写到Reduce端的缓存中,同样缓存占用到达一定阈值后数据写入磁盘中,同样会进行Partition、Combine、排序等过程。如果形成了多个磁盘文件还会进行合并,最后一次合并的结果作为Reduce的输入而不是写入到磁盘中。③Reduce的参数:最后将合并后的结果作为输入传入Reduce任务中。

      

    Hadoop中的压缩:Shuffle过程中看的,Map端在写磁盘的时候才用压缩的方式将Map的输出结果进行压缩是一个减少网络开销很有效的方法。压缩算法的实现:①Codec。Codec是Hadoop中关于压缩,解压缩的算法的实现,在Hadoop中,Codec由CompressionCode的实现来表示。

    ②MapReduce的输出进行压缩。

    ③在Java中设置输出压缩。

   

四、MapReduce排序分组

  

  在Hadoop默认的排序算法中,只会针对Key值进行排序。我们可以自定方式重写排序函数

    定义:

               

public interface WritableComparable<T> extends Writable, Comparable<T> {
}

   自定义类型实现WritableComparable的接口,该接口中有一个compareTo()方法,当对key进行比较时会调用该方法,而我们将其改为了我们定义的比较规则,从而实现我们想要的效果。
 

 

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值