自定义的分区函数有时会导致数据倾斜的问题,即有的分区数据量极大,各个分区数据量不均匀,这会导致整个作业时间取决于处理时间最长的那个reduce,应尽量避免这种情况发生。
combiner(map端的reduce)集群的带宽限制了mapreduce作业的数量,因此应该尽量避免map和reduce任务之间的数据传输。hadoop允许用户对map的输出数据进行处理,用户可自定义combiner函数(如同map函数和reduce函数一般),其逻辑一般和reduce函数一样,combiner的输入是map的输出,combiner的输出作为reduce的输入,很多情况下可以直接将reduce函数作为conbiner函数来使用(job.setCombinerClass(FlowCountReducer.class);)。combiner属于优化方案,所以无法确定combiner函数会调用多少次,可以在环形缓存区溢出文件时调用combiner函数,也可以在溢出的小文件合并成大文件时调用combiner。但要保证不管调用几次combiner函数都不会影响最终的结果,所以不是所有处理逻辑都可以使用combiner组件,有些逻辑如果在使用了combiner函数后会改变最后rerduce的输出结果(如求几个数的平均值,就不能先用combiner求一次各个map输出结果的平均值,再求这些平均值的平均值,这将导致结果错误)。
combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量。(原先传给reduce的数据是(a,(1,1,1,1,1,1...)),使用combiner后传给reduce的数据变为(a,(4,2,3,5...)))
分组分组和上面提到的partition(分区)不同,分组发生在reduce端,reduce的输入数据,会根据key是否相等而分为一组,如果key相等的,则这些key所对应的value值会作为一个迭代器对象传给reduce函数。以单词统计为例,reduce输入的数据就如:第一组:(a,(1,3,5,3,1))第二组:(b,(6,2,3,1,5))。上述例子也可以看出在map端是执行过combiner函数的,否则reduce获得的输入数据是:第一组:(a,(1,1,1,1,1,...))第二组:(b,(1,1,1,1,1...))。对每一组数据调用一次reduce函数。
值得一提的是如果key是用户自定义的bean对象,那么就算两个对象的内容都相同,这两个bean对象也不相等,也会被分为两组。如上述流量统计案例里自定义的flowbean对象,就算是上行流量下行流量相等的两个flowbean对象也不会被分为一组。这种bean作为key的情况下,如果处理逻辑需要将两个bean归为一个组,则需要另外的方法(我会在之后的文章中给出)。
排序在整个mapreduce过程中涉及到多处对数据的排序,环形缓存区溢出的文件,溢出的小文件合并成大文件,reduce端多个分区数据合并成一个大的分区数据等都需要排序,而这排序规则是根据key的compareTo方法来的。
map端输出的数据的顺序不一定是reduce端输入数据的顺序,因为在这两者之间数据经过了排序,但reduce端输出到文件上显示的顺序就是reduce函数的写出顺序。即使在没有reduce的情况下,map端处理完数据后将数据保存在文件上的顺序也不是map函数的写出顺序
MapTask和ReduceTask的并行度有几个maptask是由程序决定的,默认情况下使用FileInputFormat读入数据,maptask数量的依据有一下几点:
1.文件大小小于128M(默认)的情况下,有几个文件就有几个maptask
2.大于128M的文件,根据切片规则,有几个分片就有几个maptask
3.并不是maptask数量越多越好,太多maptask可能会占用大量数据传输等时间,降低集群计算时间,降低性能。大文件可适当增加blocksize的大小,如将128M的块大小改为256M或512M,这样切片的大小也会增大,切片数量也就减少了,相应地减少maptask的数量。如果小文件太多,可用上述提到过的小文件优化策略减少maptask的数量。
有几个reducetask是用户决定的,用户可以根据需求,自定义相应的partition函数,将数据分成几个区,相应地将reducetask的数量设置成分区数量。(设置5个reducetask,job.setNumReduceTasks(5))
YARN1、用户提交的程序的运行逻辑对yarn是透明的,yarn并不需要知道。
2、yarn只提供运算资源的调度(用户程序向yarn申请资源,yarn就负责分配资源)。
3、yarn中的老大叫ResourceManager(知道所有小弟的资源情况,以做出资源分配),yarn中具体提供运算资源的角色叫NodeManager(小弟)。