Partition分区之底层源码解析

shuffle机制之Partition分区

一、分区概念

分区概念:将数据按照条件处理后,最终输出到多个文件中.

二、源码解析

2.1 通过设置分区数实现分区效果

默认情况下,我们运行WodCount案例可以看到,在输出路径中,所有的数据都存储到一个文件中(part-r-00000)
那么多个分区对应的就是多个不同的文件,比如part-r-00001、part-r-00002…

思考1:为什么设置reduce的个数,就可以实现分区的效果?
首先默认情况下,通过源码MapTaskrun()方法找到runNewMapper(//347行)方法进入~找到output = new NewOutputCollector(//782行)方法进入~查看下面代码并解析

//此位置获取的就是在Driver类中设置的reduce个数,如果没有设置默认就是1个
partitions = jobContext.getNumReduceTasks();				-711if (partitions > 1) {
//如果说reduce的个数大于1, 会尝试获取一个分区器类,通过mapreduce.job.partitioner.class参数获取,
// 默认mapreduce.job.partitioner.class没有配置,则直接返回HashPartitioner.class 。
    partitioner = (org.apache.hadoop.mapreduce.Partitioner<K,V>)	--partitioner分区器对象
    ReflectionUtils.newInstance(jobContext.getPartitionerClass(), job);
//查看getPartitionerClass()源码~找JobContextImpl(232行)类~查看getClass()方法
//查看【mapred-default.xml】~mapreduce.job.partitioner.class未设置值~使用HashPartitioner
} else {				--partitions不大于1,默认是1
	// 最终的分区号就是固定的0号分区。
    partitioner = new org.apache.hadoop.mapreduce.Partitioner<K,V>() {
    @Override
    public int getPartition(K key, V value, int numPartitions) {
            return partitions - 1;			--默认使用的是HashPartitioner分区,返回0,即0号分区
       }
   };
}

源码解析得出结论:
有多少个分区是由reduce个数决定的,
设置reduce的个数后,源码层面是通过生成一个分区器对象,而分区器对象中的业务处理就是计算最终要分区的个数(通过重写getPartition()方法),所以说,设置了reduce的个数就实现了分区的效果。

2.2 获取到的分区器在哪里使用

通过源码逐步分析:
1、context.write(outk,outv);		  //--Mapper中的map()方法写出数据到缓冲区,查看源码
2、进入write()方法~TaskInputOutputContext接口~(ctrl+alt+B)查找该接口实现类~进入ChainMapContextImpl类(108行)~output.write()~进入RecordWriter抽象类~查找该抽象类的实现类NewOutputCollector(在MapTask中705行)~找到NewOutputCollector类中的write()方法726@Override
public void write(K key, V value) throws IOException, InterruptedException {
//collector可以看作就是缓冲区对象,它去收集kv,并同时通过分区器对象获取的分区号,所以在数据写出到缓冲区之前,分区号就已经是计算出来的
     collector.collect(key, value,
                 partitioner.getPartition(key, value, partitions));
}

2.3 分区的数据具体

1、首先明确一点,数据的分区是由分区器(Partitioner)对象来决定的.
2、Hadoop有默认的分区器对象 HashPartitioner . --通过源码可以看到
HashPartitioner会按照k的hash值对Reduce的个数进行取余操作~得到k所对应的分区.
3、hadoop也支持用户自定义分区器

//HashPartitioner默认分区器具体是如何进行分区号计算的?
//通过ctrl+N查找HashPartitioner类(mapreduce包下)~查看getPartition()方法
public int getPartition(K key, V value,int numReduceTasks) {
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}

源码分析得出结论:
通过计算每个key的hash值和Int类型的最大值做 与运算,然后对设置的reduce个数进行 取余操作,最终得到分区号。
通过取余操作,余数是0的数据,就进入0号分区文件中,余数是1的,就进入1号分区文件中
与运算的作用是保证得到的数值是正数。
注意:分区的计算不一定是非要按照key进行计算,HADOOP默认情况是通过key计算分区号,也可以自己定义按照value或者key+value等等。

三、自定义分区器

1、自定义分区类需要继承org.apache.hadoop.mapreduce.Partitioner抽象类
2、使用自定义分区器需要在Driver类中通过job.setPartitionerClass(MyPartitioner.class)设置
3、正常情况下,根据分区器业务来决定设置多少个,说白了就是分区器的逻辑会生成多少个分区,则设置的多少个reduce

四、设置分区个数的注意事项

  1. reduce个数的设置
    如果不设置,reduce的个数默认为1 ,则最终的分区号是固定的 0
    如果 1 < reduce个数 < 分区数, 报错
    如果 reduce个数 > 分区数, 报错, 多出的reduce空跑一趟.
    最佳: reduce的个数就设置为实际的分区数.
  2. 分区号只能从0开始,逐一累加
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值