MR的shuffle相关总结

在这里插入图片描述

mapreduce流程总结:
1.通过InputFormat读取切片的数据,以<k1,V1>(K表示偏移量,V表示一行数据)的形式进入map()方法进行逻辑处理,处理之后的数据<K2,V2>(K2为标识符,V2为自定义的值)会通过partition分区进入到map shuffle阶段
2.在进入到map shuffle阶段时会先进入环形内存缓冲区,默认100M,当缓冲区数据到达阈值的80%时(即数据到80M)会进入溢写阶段(即将数据写入到磁盘),溢写时会进行sort、combine,压缩(设置压缩的话才会发生)然后生成多个小文件,然后经过merge合并为大文件,此时map shuffle结束
3.mapreduce单独启动一个线程从map端拉取数据,然后进入到reduce shuffle的环形内存缓冲区,reduce shuffle阶段开始,当缓冲区数据到达阈值的80%时进入溢写阶段,溢写时会进行sort、分group、压缩(设置压缩的话才会发生)然后生成多个小文件,再经过merge合并为大文件,reduce shuffle阶段结束
4.然后以<K3,list(V1,V2…)>(K3还是标识符,V为相同K3的值的list集合)的形式进入reduce()方法进行归约,最后将结果<K4,V4>(此时K4,V4为自定义输出)输出到hdfs中


在map shuffle阶段溢写过程中会进行:
1.排序(默认按照字典顺序进行排序)
2.combine合并(在maptask里面的合并)
3.merge合并(小文件合并为大文件)
4.压缩(如果设置数据压缩的话会执行)
在reduce shuffle阶段溢写过程中会进行:
1.排序(默认按照字典顺序进行排序)
2.分组(将K相同的V放在一个list容器中)
3.merge合并(小文件合并为大文件)
4.压缩(如果设置数据压缩的话会执行)


关于如何切片的: 默认情况下一个数据块对应一个split,一个split对应一个maptask 但是: 比如文件大小是260M ,如果一个切片的大小的块是128M,按照我们之前学的是先将260M 分出一个128M,也就是还剩下132M。此时 剩下的132M里面会在去分128M 和最后一个4M 作为一个独立的block块。也就是分了三个块,第一个是128M,第二个是128M,第三个4M ,那么split的数量是不是也是3呢??通过跟踪源码发现 却不是这样的: 第一次获得块的大小128M,通过一个While(文件的剩余大小/128>1.1)?为真就切一个块为128M的。如果不为真就将剩下的放在一起,作为一个独立的Spilt。
比如文件大小260M,每一个块大小分为128M。while:(260/128=2.03>1.1?) 此时切128M剩下132M(132/128=1.03>1.1?)此时不大于 所以 将132M 放在一个切片。也就是实际是将260M 分成了两个Spilt, 一个是128M 一个是132M,这样两个split切片就对应了两个MapTask个数,reduceTask的个数跟partition分区的个数默认是有关系的,一般来说几个partition分区就对应了几个reduceTask的个数,但是如果你通过job.setNumReduceTasks()去强行设置reduceTask的个数多于分区的个数也是可以的,只不过最终生成的文件中,部分文件可能为空的,因为分区数量限制了数据最终到哪个reduce中,但是如果你通过job.setNumReduceTasks()设置的reduceTask的个数为1,而你自定义的分区的个数为多个,那么最终还是会生成一个文件,这样就会让你的自定义分区器失效。所以总结来说,reduceTask的个数>=分区的个数,但是如果reduceTask的个数<分区的个数的话,那么reduceTask的个数只能设置为1,因为reduceTask的个数<分区的个数的时候,设置为其它值是会报错的,所以reduceTask的个数不能小于分区的个数,如果要小于,就只能为1。


partition 分区的实质: 就是决定数据由哪个reducetask来处理,默认是一个分区,几个分区就对应几个输出文件
自定义partition:默认的分区类 HashPartitioner
1.extends Partitioner
2.泛型数据类型是map的输出数据类型
3.重写 getPartition 方法 返回分区编号
4.job.setPartitionerClass(MyPartition.class) 指明自定义分区类 job.setCombinerClass(Reducer.class) 指明combine数据合并的类(默认就是Reducer)
job.setNumReduceTasks(分区的个数); 指明分区的个数


merge合并小文件的方式有三种:
1.内存到磁盘(默认方式)
2.内存到内存
3.磁盘到磁盘


一般来说 一个数据块对应一个split,一个split对应一个maptask(maptask是并行计算的)
一般来说 partition分区的个数与reducetask的个数相同,reducetask的个数与最终生成结果文件的个数相同


1.如何自定义数据类型?
自定义数据类型需要自定义类实现Writable或WritableComparable接口,然后重写hashcode()、equals()、readFiles()、write()、compareTo(),toString()方法
2.如何自定义分区?
自定义分区需要extends Partitioner类 重写getPartition()方法,将分区逻辑写入getPartition()中,通过
job.setNumReduceTasks(); //设置ReduceTasks的数量
job.setPartitionerClass(MyParatition.class);//设置自定义分区类
job.setCombinerClass(Reducer.class);//设置Combiner合并的类(默认是Reduce类)
3.多文件输出?
多文件输出通过MultipleOutputs类写出数据,写出要分文件的逻辑,然后通过MultipleOutputs.addNamedOutput(job对象, “文件名”, TextOutputFormat.class, 输出k的类型, 输出v的类型);
4.分布式缓存的类怎么设置?
即在map端,通过DistributedCache.getLocalCacheFiles(),传入一个Configuration对象,返回一个Path数组,然后通过io流可以读入数据,通过job.addCacheFile(new URI())设置要读入缓存的文件
5,自定义Combiner(默认的combiner类是Reducer)
1.extends Reducer(泛型类型分别是map端的输出类型和reduce端的输入类型,一样)
2.重写reduce()方法


mr join? 实现思想?
mapreduce join分为map端join和reduce端join
map端join又叫分布式缓存,即通过通过DistributedCache.getLocalCacheFiles(),传入一个Configuration对象,返回一个Path数组,然后通过io流可以读入数据,通过job.addCacheFile(new URI())设置要读入缓存的文件
reduce端join即通过在map端把关键字作为key输出,并在value中标记出数据是来自data1还是data2,在reduce阶段,判断每一个value是来自data1还是data2,在内部分成两组,做集合的乘积


mapreduce数据压缩发生在map端的溢写过程中和reduce端的溢写过程中
mapreduce的压缩类型分为3种:
record(默认,压缩单独的记录),none,block(可以压缩一组记录。由于它有更好的压缩比,所以推荐使用)
mapreduce的压缩方式(又叫压缩算法)为6种:
deflate(默认的) 对应的类为:DefaultCodec
gzip ---- GzipCodec
bzip2 ---- BZip2Codec
LZO ---- LzoCodec
LZ4 ---- Lz4Codec
Snappy ----SnappyCodec
map端压缩需要设置的:
打开map输出压缩设置
conf.setBoolean(“mapred.compress.map.output”, true); 设置使用的压缩算法
conf.setClass(“mapred.map.output.compression.codec”,GzipCodec.class,
CompressionCodec.class);
reduce端压缩需要设置的: 打开Reduce输出压缩设置
FileOutputFormat.setCompressOutput(job, true); 设置使用的压缩算法
FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值