Map/Reduce简介
MapReduce是Google公司的核心计算模型,它将运行于大规模集群上的复杂的并行计算过程高度地抽象为两个函数:Map和Reduce。Hadoop中的MapReduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千台商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上T级别的数据集,实现了Hadoop在集群上的数据和任务的并行计算与处理。
一个Map/Reduce作业(Job)通常会把输入的数据集切分为若干独立的数据块,由Map任务(Task)以完全并行的方式处理它们。框架会先对Map的输出进行排序,然后把结果输入给Reduce任务。通常作业的输入和输出都会被存储在文件系统中。整个框架负责任务的调度和监控,以及重新执行已经失败的任务。
通常,Map/Reduce框架和分布式文件系统是运行在一组相同的节点上的,也就是说,计算节点和存储节点在一起。这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这样可以使整个集群的网络带宽得到非常高效的利用。
Map/Reduce 框架由一个单独的Master JobTracker 和集群节点上的Slave TaskTracker 共同组成。Master 负责调度构成一个作业的所有任务,这些任务分布在不同的slave上。Master监控它们的执行情况,并重新执行已经失败的任务,而Slave仅负责执行由Master指派的任务。
在Hadoop上运行的作业需要指明程序的输入/输出位置(路径),并通过实现合适的接口或抽象类提供Map和Reduce函数。同时还需要指定作业的其他参数,构成作业配置(Job Configuration)。在Hadoop的JobClient 提交作业(JAR包/可执行程序等)和配置信息给JobTracker 之后,JobTracker 会负责分发这些软件和配置信息给slave及调度任务,并监控它们的执行,同时提供状态和诊断信息给JobClient。
Map/Reduce 计算模型
在Google发表论文时,MapReduce的最大成就是重写了Google的索引文件系统。而现在,谁也不知道它还会取得多大的成就。MapReduce被广泛地应用于日志分析、海量数据排序、在海量数据中查找特定模式等场景中。但是,我们终究不得不承认,MapReduce终究不是万能的,它有自身使用的特定场景。
JOBS
Hadoop MapReduce Jobs可以切分成一系列运行于分布式集群中的map和reduce任务,每个任务只运行全部数据的一个指定的子集,以此达到整个集群的负载平衡。Map任务通常加载,解析,转换,过滤数据,每个reduce处理map输出的一个子集。Reduce任务会去map任务端获取中间数据来完成分组,聚合。用这样一种简明直接的范式,从简单的数值聚合到复杂的join操作和笛卡尔操作。
INPUT
MapReduce的输入是hdfs 上存储的一系列文件集。在hadoop中,这些文件被一种定义了如何分割一个文件成分片的input format来分割,一个分片是一个文件基于字节的可以被一个map任务加载的一个块。
MAP
每个map任务被分为以下阶段:record reader,mapper,combiner,partitioner。Map任务的输出叫中间数据,包括keys和values,发送到reduce端。运行map任务的节点会尽量选择数据所在的节点。这种情况下,不会出现网络传输,在本地节点就可以完成计算。
Record reader
Record reader会把根据input fromat生成输入分片翻译成records。Record reader的目的是把数据解析成记录,而不是解析数据本身。它把数据以键值对的形式传递给mapper。通常情况下键是偏移量,值是这条记录的整个字节块。
Map
Map阶段,会对每个从record reader处理完的键值对执行用户代码,这些键值对又叫中间键值对。键和值的选择不是任意的,并且对MapReduce job的成功非常重要。键会用来分组,值是reducer 端用来分析的数据。这本书会在设计模式方面提供大量的细节去解释键值对的选择。设计模式之间一个主要的区别是键值对的语义。
Combiner
Combiner是一个map阶段聚合数据的部件,相当于一个局部reducer,它是可选的。它根据用户提供的方法在一个mapper范围内根据中间键去聚合值。例如:数的总和是各个部分数量的和,你可以先计算中间的数目,最后再把所有中间数目加起来。很多情况下,这样能减少数据的网络传输量。发送(hello world 1)三次很显然要比发送(hello world3)需要更多的网络传输字节量。Combiners 可以被广泛的模式替换。很多Hadoop开发者忽视combiner,但能获得更好的性能。我们需要指出的是哪一种模式用combiner有好处,哪一种不能用combiner。Combiner 不会保证总会执行,所以它是一个整体逻辑。
Partitioner
Partitioner会获取从mapper(或combiner)来的键值对,并分割成分片,每个reducer一个分片。默认用哈希值,典型使用md5sum。然后partitioner 根据reduce的个数执行取余运算:
key.hashCode()%(number of reducers)这样能随即均匀的根据key分发数据到reduce,但仍然要保证不同mapper的相同key 要到同一个reduce。Partitioner也可以自定义,使用更高级的样式,例如排序。然而,更改partitioner很少用。Partitioner的每个map的数据会写到本地磁盘,并等待对应的reducer检测,拿走数据。
REDUCE
Reduce任务分为以下阶段:shufle,sort,reduce,output format
Shuffle and sort Reduce任务开始于shuffle和sort阶段。这一阶段获取partitioner的输出文件,并下载到reduce运行的本地机器。这些分片数据会根据key合并,排序成一个大的数据文件。排序的目的是让相同的key相邻,方便在reduce阶段值得迭代处理。这一阶段不能自定义,由框架自动处理。需要做的只是key的选择和可以自定义个用于分组的比较器。
Reduce
Reduce任务会把分组的数据作为输入并对每个key组执行reduce方法代码。方法会传递key和可以相关的所有值得迭代集合。很多的处理会在这个方法里执行,也就会有很多的模式。
一旦reduce 方法完成,会发送0或多个键值对到output format跟map一样,不同的 reduce依据不同的逻辑情形而不同。
output format
output format会把reduce阶段的输出键值对根据record writer写到文件里。默认用tab分割键值对,用换行分割不同行。这里也可以自定义为更丰富的输出格式,最后,数据被写到hdfs,你可以自定义输出格式。