MapReduce流程、任务数设置
一、MapReduce的优缺点
1、优点
- 易于编程:简单的实现一些借口即可完成一个分布式程序。
- 扩展性好:简单的增加机器就可以扩展计算能力
- 高容错性:hadoop内部就可以完成计算任务转移
- 高吞吐量:PB级以上数据的离线处理
2、缺点
- 实时计算:无法像Mysql那样在毫秒或秒级内返回结果
- 流式计算:输入数据是静态的,不能动态变化
- DAG(有向图)计算:计算效率低下
二、MapReduce中combiner和partitioner的作用
- Combiner:Map端按Key聚合,以减少Reducer提取数据的传输负载,可以没有,使用的前提是同一个分区存在重复键Key
- Partitioner:如果ReduceTask>1,Partitioner决定键值进入哪个Reducer
三、MapReduce的整体流程
1、通过XxxInputformat获取切片信息InputSplit[],并提交到yarn上,然后AM据此信息计算开启的MapTask数量
- 并发启动MapTask(一个InputSplit一个MapTask)
2、MapTask通过RecordReader读取信息,从输入InputSplit中解析出一个个key/value
- 每读完一行创建一个Mapper并将行偏移量LongWritable,行内容Text作为Mapper的输入
3、Mapper通过map方法处理数据形成以键XxxKeyWritable和值XxxValueWritable的结果数据
- 将处理结果通过Context的write方法写出,得到的也是一系列新的key/value
shuffle过程:MapTask端
4、调用收集器收集Mapper发送的数据到环形缓冲区,在收集器内部会调用Partitioner进行数据分区
- 【OutputCollector】 -write->
5、环形缓冲区数据量达到80%时溢出(每次溢出写到磁盘之前都会进行分区排序,形成一个文件),每次排序都是双重排序,先按分区排序,再按键Key排序
- 【CircularBuffer】 -reach 80% partition & sort spill->
6、将所有的临时小文件分区排序合并成一个大文件。
- 在此过程,对于某个分区,采用多轮递归合并的方式进行排序
- 【SmallFiles -partition】 [& combineByKey] &sortByKey merge->
7、形成的大文件是按照分区和键值双重排序的
【BigFile -partitioned】 [& combinedByKey] & sortedByKey_in_partition->
shuffle过程:ReduceTask
8、所有MapTask都结束后,ReduceTask启动,并主动的从所有的MapTask端拷贝属于该分区的数据,每个拉取到的都是一个文件
- <-fetch_by_partitionNo from all maptask -
9、根据键排序合并所有MapTask端的小文件为一个大文件
- 远程拷贝时,会启动两个后台线程对内存和磁盘上的文件进行合并
- 对在map端已经做过局部排序的数据进行一次归并排序
- 【SmallFiles】 -sortByKey merge->
10、分组提取合并数据信息,一个分组(一个Key)一个Reducer
- 【BigFile 】-groupByKey->
11、Reducer通过reduce方法处理分组数据形成XxxKeyWritable和XxxValueWritable的结果数据
- 将处理结果通过context的write方法写出到HDFS上
12、XxxOutputFormat收集Reducer发送的数据
- 收集完成后落盘
四、MapTask和ReduceTask的数量如何决定?如何调整数量
1、MapTask的数量由以下因素决定
-
mapred-site.xml 切片的大小配置 :
minSplitSize = mapred.min,split.size
maxSplitSize = mapred.max.split.size -
hdfs-site.xml 块的大小配置,默认是128Mb
公式:
- InputSplitSize = Math.max(minSplitSize,Math.min(maxSplitSize,blockSize))
- maptaskCount = Math.ceil(fileSize/inputSplitSize)
2、ReduceTask的数量一般在job中设置
- reducetaskCount = job.setNumReduceTasks(int N);
五、Map Join和Reduce Join的区别
1、map join:
-
理解1:大表+小表,小表放在缓存里,join的过程在map端直接把缓存里的数据提出来然后聚合就完成了,省去了reduce的过程
-
理解2:如果是大表加小表,他是有一个分布式缓存机制把小表分配到各个节点的内存上,然后在具体的maptask里,把小表join进去,直接落盘,落盘的结果就是join小表的大表(行数没变,只是增加了小表join进去的列)
2、reduce join:
-
理解1:大表+大表,两张大表之间存在一对一的匹配关系,在map端只能关联不能算,在reduce端进行分组,shuffle过程负载更高,reduce端计算量更大,而且容易产生数据倾斜
-
理解2:如果是大表+大表,这两个表都是分布在各个maptask上的,所以需要reduce汇总。具体到maptask的操作,是以join的条件也就是on作为key,然后两张表匹配到on的数据集合作为value,然后通过context.write方法出去,后面正常进行shuffle和reduce
3、Distributedcache分布式缓存:
- 为了减少数据倾斜,可在map端缓存多张表,提前处理业务逻辑
- 在mapper的setup阶段,将文件读取到缓存集合中,然后在驱动函数中加载缓存到运行节点:job.addCacheFile(new URI(“file:/d:/mapjoincache/hello.txt”));
六、30T的数据,只有3台机器,每台设备128G内存,要启动多少Maptask?如何去设置
-
首先要知道,一个切片对应一个MapTask,一个MapTask对应一个Container,每个Container和JVM是绑定在一起共生共灭的
-
然后是切片的大小,节点少时,切片要设置的大一些,减少Container的启动注销频率,一般来说设置1-4G,具体需要测试。我们在这设置为4G。4G的切片,理想情况下需要一个4G内存的container(可以理解为在map端写入磁盘前可能最多会有4G的数据放在内存中)
-
一个切片需要4G的container,那么128G内存假设可把3/4的内存也就是96G用于MapTask,那么一台机器理论上那就是96/4=24个Container同时运行,也就是一台机器同时运行的MapTask为24个,三台机器的可以并发72个MapTask。
-
具体切片大小的设置,就是设置的参数minSplit maxSplit 和文件块的大小做比较,maxSplit和文件块比较选取最小值,然后再和minSplit比较选取最大值。总而言之,把minSplit和maxSplit都调大就行。比如4G,5G。