分组分区和数据倾斜combiner

reducetask的并行度----分区:
    yarchild--            1maptask---MyMapper/1reducetask任务----MyReducer
    运行reduce任务的并行度
    目前情况下  reducetask只有一个
    19557 YarnChild    ---   reducetask
    默认情况下  reducetask的个数只有1个
        一个reducetask只能运行在一个节点上
        当数据量很大时候  只有一个reducetask不合理的  
            1)这个reducetask的压力很大
            2)负载不均衡
        reducetask也应该根据我们的实际的数据  设置多个
            如何设置:
                代码设置:
                    job.setNumReduceTasks(tasks);
                    参数代表就是reducetask的个数  需要几个reducetask的时候  设置为几就可以
                    这个参数值  默认为1  默认情况只运行一个reducetask
                    job.setNumReduceTask;
                    发现   输出的结果3个文件   1个标志文件
                        part-r-00000
                        part-r-00001
                        part-r-00002
                    结论:一个reducetask最终输出一个对应的结果文件
                    reducetask中的数据如何划分的:
                        默认情况下:
                            hash分割数据的
                            key.hash%reducetask的个数
                            一个reducetask的数据对应的是一个分区的数据
                            分区:对map输出的数据进行一个按照一定的规则划分  每一部分称为一个分区
                                    partition
                                    这里的分割规则叫分区算法
                                推断:默认的分区算法:hash算法  1)散列  2)唯一
                                
                            底层实现:
                                默认的抽象类  Partitioner抽象类   定义分区算法/分区规则的
                                public abstract class Partitioner<KEY, VALUE> {
                                    //返回值:int    这里的返回值代表的是分区编号 每一个分区的唯一标志 默认从0开始   顺序递增的
                                    //参数:参数1-map输出的key  参数2-map输出的value   参数3-分区个数(job.setNumReduceTask())
                                    public abstract int getPartition
                                    (KEY key, VALUE value, int numPartitions);
                                }
                                默认调用的实现类:HashPartitioner
                                    //泛型指的是map输出的k   v的类型
                                    public class HashPartitioner<K, V> extends Partitioner<K, V> {
                                        //默认的参数3   numReduceTasks
                                      /** Use {@link Object#hashCode()} to partition. */
                                      public int getPartition(K key, V value,
                                                              int numReduceTasks) {
                                        return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
                                      }

                                    }
                                    key.hashCode() & Integer.MAX_VALUE   目的:防止溢出  范围控制integer_max
                                       1011001100111010101010101                                        
                                    &                                    
                                        111111111111111111111111
                                        --------------------------
                                        011001100111010101010101
                            默认的分区算法   取map的key的hash值%reducetask的个数  获取返回值就是分区编号
    总结:默认情况下
        一个分区----一个reducetask----一个输出结果文件
            part-r-00001    00001---代表分区编号
        默认情况下  分区算法  hash分区
        (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
        默认情况下  分区算法  和 reducetask的个数一一对应的
        reducetask的并行度  取决于reducetask的个数   job.setNumReduceTasks
        reducetask的数据如何分配  取决于分区算法的  默认的hash分区
    自定义分区:
        默认的分区算法  并不能满足所有的需求   不能自定义数据的去向的
        假设:淘宝数据
            江苏
            浙江
            上海
            内蒙
            按照地域进行划分reducetask的数据  默认的就不可以  需要自定义分区
        写法:
            1)继承Partitioner类
            2)重写getPartition 方法  这个方法的返回值  代表就是分区编号
        案例:
            将流量汇总统计结果按照手机归属地不同省份输出到不同文件中
            手机号的前三位---手机号归属地
            输出到不同的文件-----不同的reducetask的输出---不同分区
            分区算法:按照手机号的归属地进行划分的
                归属地不同---不同分区--不同reducetask---不同文件
            自定义分区:
                分区字段map的key的位置
                按照手机号分区
                shuffle
            map端:
                key:手机号
                value:剩下的
            reduce端:
                输出
                
        //指定自定义分区
        job.setPartitionerClass(MyPartitioner.class);
        //指定reducetask的个数
        job.setNumReduceTasks(3);
        报错:
            分区编号   值3   reducetask-3个  redutask0--分区0  reducetask1=分区1  reducetask2=分区2  
            报错:    
                Illegal partition for 15013685858 (3)
                原因  分区和reducetask的个数不匹配
            注意:设定分区编号的时候  最好顺序递增的  不要跳数
            分区个数3 个  reducetask的个数可以设置:
                1=====可以   对应一个输出结果
                2=====不可以
                3可以
                >3  可以
                reducetask的个数  为1 的时候   所有的分区的数据  默认全部到一个reducetask中
                reducetask的个数大于1   按照分区编号  对应的分区到对应的reducetask中
                设置的时候reducetask的个数=分区个数
    分区算法:    
        默认分区:key.hash%reducetask的个数
        自定义分区:自己定义的
        分区算法决定map输出的数据  如何分配给reduce的
    
    
数据倾斜:
    多个reducetask并行计算的时候  某一个reducetask分配数据不均匀   这个时候产生现象数据倾斜
    后果:reducetask的整体运行的性能低
    100reducetask
    99reducetask--1T   10min
    1reducetask-----100T  1000min
    进度:
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        map  100%  reduce  99%
        ...............
    大数据中不怕数据量大  怕数据倾斜
    很快reducetask达到90%  卡
    数据倾斜一定需要尽量避免的
    原因:分区算法没有合理的分配均匀数据
    解决:合理设计分区算法  根据实际的数据抽样做测试  进行合理设计分区  业务、数据
    mapreduce阶段:
        maptask:
            1个切片默认128M---1maptask
            1)maptask的并行度比较高
                切片个数---数据块的个数(最后一个切片有可能跨块的)
            2)maptask数据一个切片  128M  对应的数据量比较小
        reducetask:
            容易产生数据倾斜
            1)并行度不高
                job.setNumReduceTasks()
                经验值:reducetask最大值  datanode*0.95  100---95
            2)reducetask的数据分配取决于分区算法  
            3)reducetask的对应的数据量本身比较大
combiner组件:
    这个组件不适用所有的场景的
    优化组件:提升性能的作用  这个组件默认不加的
    作用:对到reducetask之前的数据做预处理  帮助reducetask做预处理  减少reducetask的数据量  提升性能
    默认没有组件:
        怎么加?
        这个组件就是帮助reducetask做事情  减轻redcetask的压力
            提前帮助reducetask做一些自己的工作
            combiner业务逻辑和reducetask的逻辑一样  作用的时间点在maptask之后  reducetask之前
        怎么实现?
            这个组件不会影响业务逻辑
            和reducetask的实现是一样
            1)继承Reducer类
            2)重写reduce方法
            3)job中设置添加combiner组件
            job.setCombinerClass(MyCombiner.class);
        实现 和reducetask的实现一样 实际的开发过程直接使用reducer的类作为combiner的类
        
        combiner的可以适用:
            求和
            求最大值
            求最小值
        Combiner不使用场景:
            求平均值
    注意:这个组件使用的时候  慎重考虑
分组:
    map----shuffle-----reduce
    shuffle:分区----排序----分组
    分组到底是怎么分组的:按照map的key进行分组的
        默认的类型:
            wc:
            000000000000000000000000000
            hadoop----------------64
            hadoop----------------64
            hadoop----------------64
            hadoop----------------64
            000000000000000000000000000
            hadoophello----------------1
            hadoophello----------------1
            hadoophello----------------1
            hadoophello----------------1
            相同的key为一组
            默认的是key一直随着value指针变化而变化的 只不过默认的key都是一样的 
        自定义的类型:
            111111111111111111111111111111
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            默认的分组按照自定义类型的comparaTo的方法进行分组的
            现根据科目  再根据  成绩
            将相同科目  和  相同分数的人划分到一组
            
            111111111111111111111111111111computer    huangzitao    72.42857142857143   //这一组中的第一个key
            map:context.write(sb,null)
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            
            reduce:
    默认分组:调用的就是所有类型ComparaTo方法---排序的方法
    有的需求中 分组和排序如果有冲突,怎么办?
    案例:
        3、求出每门课程参考学生平均成绩top3的学生的信息:课程,姓名和平均分

            课程   姓名    成绩
            computer    liujialing    98
            computer    huangbo        96
            computer    liutao        95
            math        huangdatou    99
            math        liuyifei    98
            math        liutao        95
            map的输出的key:自定义类型(课程  姓名   成绩)
            排序:按照成绩
            分组:课程
            
            comparaTo(){
                先按课程
                成绩
            }
            
            实际的上的分组:comparaTo()
                按照:课程+成绩
            每个课程的前三  保证reduce一次性可以接受的数据是同一门课程的
            排序  和  分组  冲突了
            分组不能使用刚才的排序的规则的了
            排序:按照成绩
            分组:课程
            自定义分组:
                分组:课程
                分组的底层  对map输出所有的key进行比较  相同的(return 0)key 认为一组
                比较的过程中  返回的!=0   认为不是同一组
                writableComparator  分组规则的  普通类
                
                默认的分组的比较:
                  @SuppressWarnings("unchecked")
                 //map输出的key-----比较  序列化   WritableComparable
                //参数:WritableComparable
                //分组针对map输出的key
                public int compare(WritableComparable a, WritableComparable b) {
                //默认的分组就是调用  自定义的comparaTo
                    return a.compareTo(b);
                }
                
                自定义分组:重写compare
                    1)继承writableComparator
                    2)重写compare()
                    3)job中指定
                    job.setGroupingComparatorClass(MyGroup.class);
                    
                    报错:
                    java.lang.Exception: java.lang.NullPointerException
                    空指针异常的错误:
                    compare()  两个参数的对象默认不会帮我们创建的
                    
                    
                     /** Construct for a {@link WritableComparable} implementation. */
                      protected WritableComparator(Class<? extends WritableComparable> keyClass) {
                        this(keyClass, null, false);
                      }

                      protected WritableComparator(Class<? extends WritableComparable> keyClass,
                          boolean createInstances) {
                        this(keyClass, null, createInstances);
                      }

                      //参数1   比较的对象类型的class  ScoreBean
                      //参数2   配置文件对象
                      //参数3---是否创建WritableComparable  这个对象  默认false  代表不创建
                      protected WritableComparator(Class<? extends WritableComparable> keyClass,
                                                   Configuration conf,
                                                   boolean createInstances) {
                    
                    排序:分数
                    分组:课程
                    =========================
                    computer    huangjiaju    83.2-----------(null)
                    computer    huangjiaju    83.2-----------(null)
                    computer    liutao    83.0-----------(null)
                    =========================
                    math    huangxiaoming    83.0-----------(null)
                    =========================
                    english    huanglei    83.0-----------(null)
                    =========================
                    computer    liutao    83.0-----------(null)
                    先进行的排序  在进行的分组
                    排完序:
                    computer    huangjiaju    83.2-----------(null)
                    computer    huangjiaju    83.2-----------(null)
                    computer    liutao    83.0-----------(null)
                    math    huangxiaoming    83.0-----------(null)
                    english    huanglei    83.0-----------(null)
                    computer    liutao    83.0-----------(null)
                    分组在排序的基础上进行的:判断相邻的
                    computer    huangjiaju    83.2-----------(null)
                    computer    huangjiaju    83.2-----------(null)
                    computer    liutao    83.0-----------(null)
                    
                    
                    math    huangxiaoming    83.0-----------(null)
                    
                    
                    english    huanglei    83.0-----------(null)
                    
                    
                    computer    liutao    83.0-----------(null)
                    
                    排序的时候需要将分组的字段放在一起
                    
                    排序:
                    课程   分数
                    分组:
                    课程
                    
                    
                    既有排序 a b 又有分组  c
                    排序:c a  b
                    分组:c
                    排序的字段中必须包含 分组字段  分组字段必须在排序字段的前面
                    
            
            

                
            
            

补充:
    reduce中的迭代器:
        1)只能迭代一次    迭代的过程中指针的操作
            只要迭代一次  指针调到末尾
        2)迭代器中的数据对应的一组的所有的value
            这个迭代器中每一个value都对应一个自己的key
            
            
            111111111111111111111111111111computer    huangzitao    72.42857142857143
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            computer    huangzitao    72.42857142857143-----------(null)
            computer    huangxiaoming    72.42857142857143-----------(null)
            ==============computer    huangxiaoming    72.42857142857143
            每一组中的这个key是一直随着value指针移动而移动的
            每一个value都会对应一个key值

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值