第I部分Hadoop基础知识
第2章关于MapReduce
MapReduce是一种可用于数据处理的编程模型。该模型比较简单,但要想写出有用的程序却不太容易。Hadoop 可以运行各种语言版本的MapReduce程序。在本章中,我们将看到同一个程序的Java、Ruby 和Python 语言版本。最重要的是,MapReduce程序本质上是并行运行的,因此可以将大规模的数据分析任务分发给任何一个拥有足够多机器的数据中心。MapReduce的优势在于处理大规模数据集,所以这里先来看一个数据集。
在本书中举的例子是一个气象天气的例子。书籍写的很好,不过我还是比较认为,如果针对WordCount会更容易理解。
根据这两个图进行解释:
整个shuffle过程:
Java代码:
https://blog.csdn.net/qq_41946557/article/details/102307454
【注】接下来的话可根据上面的图进行分析。
在代码中:MapReduce任务过程分为两个处理阶段:map阶段和reduce阶段。每阶段都以键-值对作为输入和输出,其类型由程序员来选择。程序员还需要写两个函数: map函数和reduce函数。
首先定义一些术语。MapReduce作业(job)是客户端需要执行的一个工作单元:它包括输人数据、MapReduce 程序和配置信息Hadoop 将作业分成若干个任务(task)来执行,其中包括两类任务: map任务和reduce任务。这些任务运行在集群的节点上,并通过YARN进行调度。如果一个任务失败,它将在另一个不同的节点上自动重新调度运行。
Hadoop将MapReduce的输人数据划分成等长的小数据块,称为输人分片(input spli)或简称“分片”。Hadoop为每个分片构建一个map任务,并由该任务来运行用户自定义的map函数从而处理分片中的每条记录。
拥有许多分片,意味着处理每个分片所需要的时间少于处理整个输入数据所花的时间。因此,如果我们并行处理每个分片,且每个分片数据比较小,那么整个处理过程将获得更好的负载平衡,因为一台较快的计算机能够处理的数据分片比-一台较慢的计算机更多,且成一定的比例。即使使用相同的机器,失败的进程或其他并发运行的作业能够实现满意的负载平衡,并且随着分片被切分得更细,负载平衡的质量会更高。
另一方面,如果分片切分得太小,那么管理分片的总时间和构建map任务的总时间将决定作业的整个执行时间。对于大多数作业来说,一个合理的分片大小趋向于HDFS的一个块的大小,默认是128 MB,不过可以针对集群调整这个默认值(对所有新建的文件),或在每个文件创建时指定。
Hadoop在存储有输人数据(HDFS中的数据)的节点上运行map任务,可以获得最佳性能,因为它无需使用宝贵的集群带宽资源。这就是所谓的“数据本地化优化”(data locality optimization)。 但是,有时对于-一个map任务的输人分片来说,存储该分片的HDFS数据块复本的所有节点可能正在运行其他map任务,此时作业调度需要从某一数据块所在的机架中的一个节点上寻找一个空闲的map槽(slot)来运行该map任务分片。仅仅在非常偶然的情况下(该情况基本上不会发生),会使用其他机架中的节点运行该map 任务,这将导致机架与机架之间的网络传输。图2-2 显示了这三种可能性。
现在我们应该清楚为什么最佳分片的大小应该与块大小相同:因为它是确保可以存储在单个节点上的最大输入块的大小。如果分片跨越两个数据块,那么对于任何一个HDFS节点,基本上都不可能同时存储这两个数据块,因此分片中的部分数据需要通过网络传输到map任务运行的节点。与使用本地数据运行整个map任务相比,这种方法显然效率更低。map任务将其输出写入本地硬盘,而非HDFS。这是为什么?因为map的输出是中间结果:该中间结果由reduce 任务处理后才产生最终输出结果,而且一且作业完成,map的输出结果就可以删除。因此,如果把它存储在HDFS中并实现备份,难免有些小题大做。如果运行map任务的节点在将map中间结果传送给reduce任务之前失败,Hadoop 将在另一个节点上重新运行这个map任务以再次构建map中间结果。
reduce任务并不具备数据本地化的优势,单个reduce 任务的输入通常来自于所有mapper的输出。在本例中,我们仅有一个reduce 任务,其输入是所有map任务的输出。因此,排过序的map输出需通过网络传输发送到运行reduce任务的节点。数据在reduce端合并,然后由用户定义的reduce函数处理。reduce 的输出通常存储在HDFS中以实现可靠存储。
一个reduce 任务的完整数据流如图2-3所示。虚线框表示节点,虚线箭头表示节点内部的数据传输,而实线箭头表示不同节点之间的数据传输。
reduce任务的数量并非由输人数据的大小决定,相反是独立指定的。
如果有好多个reduce任务,每个map任务就会针对输出进行分区(partition),即为每个reduce 任务建一个分区。每个分区有许多键(及其对应的值),但每个键对应的键-值对记录都在同一分区中。分区可由用户定义的分区函数控制,但通常用默认的pritioner通过哈希函数来分区,很高效。
多个reduce任务的数据流,即最开始的分析图示。
最后,当数据处理可以完全并行(即无需混洗时),可能会出现无reduce任务的情况(示例参见8.2.2节)。在这种情况下,唯一的非本地节点数据传输是map任务将结果写人HDFS(参见下图)。
集群上的可用带宽限制了MapReduce作业的数量,因此尽量避免map和reduce任务之间的数据传输是有利的。
最后还介绍了:combiner函数、Hadoop Streaming以及使用Ruby和Python【不是很熟悉,就不多说了。】