主要的各个阶段
在Split 分片阶段, — 只需要知道有这个阶段就有了,具体大小的关系,如何计算的
所有的输入都会被分成若干个分片,即对对输入的所有文件在block中形成Z个分片。 一个分片(split)会要对应下游一个Map Task。
输入文件默认是要保存到 NataNode的block块中,Hadoop2.x默认的block大小为128MB(可以在hdfs-site.xml中设置参数dfs.block.size)
在分片阶段,所有的输入文件都会被计算分配到相应的block中, 一个DataNode默认有x个Block,对于输入的文件个数m,分别阶段就是将这m个文件计算如何去放到DataNode的各Block中(如果一个DataNode不够,可能需要增加NataNode的个数),形成Z个分片(一个block不会出现两个文件的数据)。各个文件存放在哪些DataNode的哪些Block中的分片这类相关的 元数据信息就存放在NameNode中。
延伸: 由于NameNode内存有限,大量的小文件会给hdfs带来性能上的问题。故hdfs适合存放大文件,对于大量的小文件,可以采用压缩、合并小文件的优化策略。例如,设置文件输入类型为CombineFileInputFormat格式。
分片的个数影响下游Map任务的个数,在实际情况下,map任务的个数是受多个条件制约,一般一个DataNode的Map正常的并行规模大致是每个节点(node)大约10到100个map,对于CPU 消耗较小的map任务可以设到300个左右。由于每个任务初始化需要一定的时间,因此,比较合理的情况是map执行的时间至少超过1分钟。
节点Map任务的个数控制: 增加Map个数,可增大mapred.map.tasks;减少map个数,可增大mapred.min.split.size;如果要减少map个数,但有很多小文件,可将小文件合并成大文件,再使用准则2.
Map阶段:
Mapper将输入键值对(key/value pair)映射到一组中间格式的键值对集合。
Map是一类将输入记录集转换为中间格式记录集的独立任务。Map阶段具体的处理在于定义的Mapper.py中的代码是如何定义对数据的处理的。另外,在此阶段的输出中,会考虑其value值是不是分布不均匀,如果当前的不同key对应的value值的量级相差很大,会比较容易产生数据倾斜问题,解决方式是通过设置新的随机数组成的key。
shuffle阶段: 简单说来就是讲所有相同的单词归并到一起,但是这个阶段还不会进行累加。因为最终的结果统计是在reduece阶段做的事情。shuffle阶段会生成一定个数的partition分区,partition的个数是由下游reduce的个数超参数决定的。其实中间还有个sort和partition阶段,一般用shuffle泛指shuffle与sort 了。sort里面,,框架将按照key的值对Reducer的输入进行分组 (因为不同mapper的输出中可能会有相同的key)。Shuffle和Sort两个阶段是同时进行的;map的输出也是一边被取回一边被合并的。
Hadoop里经过sort时则保证了,相同的key出现在一块,一定是相连的。所以写reducer.py的时候,就可以考虑不用如果下一个不同,则key的值的处理就可以停止了!
Reduce阶段
对相同key值的各个value进行编码处理,此(统计单词个数)即求和统计各个单词的值。对于每一个Reduce会输出一个结果,如part-r-0000,part-r-0001。注意一个reduce单元可能有多个key。Partitioner、Reduce单元、输出文件这三者的数量是相等的。Reducer阶段的具体处理在于定义的reducer.py中如何将定义的。
内部执行:
Reduce任务数量设置:
在大数据量的情况下: 通常建议将reduce任务数量设置为一个较大的值(最大值是72)。一个节点上Reduce 任务数可以通过调节参数mpred.reduce.tasks;可以在代码中调用job.setNumReduceTasks(int n)方法(此是Java的)