3.1.5 MapReduce工作流程
MapReduce就是将输入进行分片,交给不同的Map任务进行处理,然后由Reduce任务合并成最终的解。
MapReduce的实际处理过程可以分解为Input、Map、Sort、Combine、Partition、Reduce、Output等阶段,具体的工作流程如图3⁃5所示。
图3⁃5为找每个文件块中每个字母出现的次数。其中,Key表示字母,Value表示该字母出现的次数。在图3⁃5中,用4个Mapper来处理输入的文件块,分别得到了各自的统计键值对<K1,V1>,对于同一个Mapper可能同一字母在不同键值对中出现,通过Combiner将同一个Mapper产生的键值对进行合并,保证同一字母出现在一个键值对中。再通过Partitioner将所有键值对按照字母合并在一起产生list(<K2,V2>,用Reducer来对list(<K2,V2>进行统计(这里用了3个Reducer),产生最终结果键值对<K3,V3>。
在Input阶段,框架根据数据的存储位置,把数据分成多个分片(Splik),在多个结点上并行处理。Map任务通常运行在数据存储的结点上,也就是说,框架是根据数据分片的位置来启动Map任务的,而不是把数据传输到Map任务的位置上。这样,计算和数据就在同一个结点上,从而不需要额外的数据传输开销。
在Map阶段,框架调用Map函数对输入的每一个<key,value>进行处理,也就是完成Map:<K1,V1>→list(<K2,V2>)的映射操作。
在Sort阶段,当Map任务结束以后,会生成许多<K2,V2>形式的中间结果,框架会对这些中间结果按照键进行排序。图3⁃5就是按照字母顺序进行排序的。

图3⁃5 MapReduce工作流程(https://www.daowen.com)
在Combine阶段,框架对于在Sort阶段排序之后有相同键的中间结果进行合并。合并所使用的函数可以由用户进行定义。就是把K2相同(也就是同一个字母)的V2值相加的。这样,在每一个Map任务的中间结果中,每一个字母只会出现一次。
在Partition阶段,框架将Combine后的中间结果按照键的取值范围划分为R份,分别发给R个运行Reduce任务的结点并行执行。分发的原则是,必须保证同一个键的所有数据项发送给同一个Reduce任务,尽量保证每个Reduce任务所处理的数据量基本相同。框架把字母a、b、c的键值对分别发给了3个Reduce任务。框架默认使用Hash函数进行分发,用户也可以提供自己的分发函数。
在Reduce阶段,每个Reduce任务对Map函数处理的结果按照用户定义的Reduce函数进行汇总计算,从而得到最后的结果。在图3⁃5中,Reduce计算每个字母在整个文件中出现的次数。只有当所有Map处理过程全部结束以后Reduce过程才能开始。
在Output阶段,框架把Reduce处理的结果按照用户指定的输出数据格式写入HDFS中。
在MapReduce的整个处理过程中,不同的Map任务之间不会进行任何通信,不同的Reduce任务之间也不会发生任何信息交换。用户不能够显式地从一个结点向另一个结点发送消息,所有的信息交换都是通过MapReduce框架实现的。
MapReduce计算框架实现数据处理时,应用程序开发者只需要负责Map函数和Reduce函数的实现。MapReduce计算框架之所以得到如此广泛的应用,就是因为应用开发者不需要处理分布式和并行编程中的各种复杂问题。如分布式存储、分布式通信、任务调度、容错处理、负载均衡、数据可靠等,这些问题都由Hadoop MapReduce框架负责处理,应用开发者只需要负责完成Map函数与Reduce函数的实现。