Hadoop学习笔记:分布式计算引擎MapReduce

MapReduce简介

MapReduce源自于Google发表于2004年12月的MapReduce论文,Hadoop MapReduce是Google MapReduce克隆版。

MapReduce源于函数式编程,包括Map和Reduce两个算子,它是一个通用的计算引擎,所以易于编程,可以实现任意的算法,表达能力很强,只是效率有区别。

MapReduce是一个分布式应用框架,解决数据导入读取,用户只需要关心如何处理数据(Map方法和Reduce方法),可以支持数据规模不断增大,机器数量的增多不会影响程序运行。分布式计算以及资源协调的错误处理由计算框架内部处理。

MapReduce有以下特点:易于编程;良好的扩展性;高容错性;适合PB级以上海量数据的离线处理,PB级数据的处理,各个节点的通信花费的时间远远超过计算的时间,MapReduce可以解决这些问题。

搜索引擎建索引是MapReduce出现的背景,另外,MapReduce也适合海量数据查找,适合大数据批量处理,比如从海量日志问价中搜索异常信息;MapReduce可以做数据统计,比如网站pv(page view)和uv(user view)的简单数据统计,以及聚类算法、分类算法、推荐算法和图算法(比如搜索引擎算网页相关性)等一些复杂数据分析算法。MapReduce是一个通用的计算引擎,各种算法都可以通过Map和Reduce两个算子来实现,通用性很强,数据多轮计算,可以减少误差,但效率不一定高。

MapReduce不适合:

  • 实时计算
    不能像MySQL一样,在毫秒级或者秒级内返回结果,这是因为MapReduce是为大规模数据批量处理准备,具有比较大的启动开销(环境的准备,数据的准备等),所以不适合做到实时计算;

  • 流式计算(数据源不断变化)
    MapReduce的输入数据集是静态的,不能动态变化,这是MapReduce自身的设计特点决定的,因为MapReduce有可能多次计算,所以如果数据不是静态的,那么不同次的计算就会不一样;

  • DAG(有向无环图)计算
    DAG是多个应用程序存在依赖关系,后一个应用程序的 输入为前一个的输出。MapReduce计算由多个子任务组成,子任务有各种依赖,必须将前面依赖的任务完成后才能继续后续的任务。MapReduce要将依赖关系转换为Map和Reduce两个算子,转换的过程遇到的问题就是数据无法共享,如果把数据共享到HDFS上,这样会产生大量的IO,会影响整个MapReduce的效率。

MapReduce编程模型

通过Wordcount示例解释:
问题:有一批文件(规模为TB级或 者 PB级),如何统计这些文件中所有单词出现的次数;
类似应用场景:搜索引擎中,统计最流行的K个搜索词; 统计搜索词频率,帮助优化搜索词提示。
方案1:用一个程序去读取和统计文件中所有单词出现的次数。
这个方案具有以下缺点:
1)执行效率低,用时长;
2)单点故障,造成程序停止;
3)网络传输效率低,IO消耗大;
4)如果文件太大,加载不到内存,那么这个程序是运行不了的,这是主要问题。

方案2:启动多个程序,分别读取不同文件中的单词出现次数,然后将这些结果进行合并。
这个方案具有以下优点:
1)本地计算,避免网络开销,IO效率高;
2)需要的内存减少;
3)执行效率高。

MapReduce使用方案2的分布式处理:把大任务拆分成小任务(Map过程),并行调度和执行小任务,将各个小任务计算后的结果聚合到一起(Reduce过程)。任务的拆分、执行和聚合都由框架自动完成,用户只需要关心输入和输出就好。

MapReduce将作业的整个运行过程分为两个阶段Map阶段和Reduce阶段

  • Map阶段由一定数量的Map Task组成
    输入数据格式解析:InputFormat (默认TextInputFormat)
    输入数据处理:Mapper
    数据分组:Partitioner
  • Reduce阶段由一定数量的Reduce Task组成
    数据远程拷贝,按照key排序
    数据处理:Reducer
    数据输出格式:OutputFormat(默认TextOutputFormat)

首先需要告诉Inputformat读取哪些文件或文件夹,InputFormat会把原始数据分片(InputSplit),一般用128M分片,将分片数据解析成key和value对,默认实现是TextInputFormat,key是行的偏移量,value是行的值,若行被截断,则读取下一个Block(HDFS中最小的数据存储单位,默认是128MB)的前几个字符,这由Map Task处理。

Split是MapReduce中最小的计算单元,默认与Block一一对应,Split与Block的对应关系是任意的,由用户控制。一个Inputformat会分成多个分片Split,一个Split只能被一个Task处理。

Combiner是一种优化,处于Map阶段,在Partition之前。Combiner可看做Local Reducer,合并相同的key对应的value(wordcount例子),通常与Reducer逻辑一样。它可以减少Map Task输出数据量(磁盘IO),减少Reduce-Map网络传输数据量(网络IO)。适合结果可以叠加的应用,平均计算不适合。
在这里插入图片描述
Partitioner决定了Map Task输出的每条数据交给哪个Reduce Task处理。Partitioner是key和Reducer的映射关系,key由哪个Reducer处理由Partitioner决定。每个Partitioner处理自己分区的数据。默认实现:hash(key) mod R (R是Reduce Task数目)。很多情况需自定义Partitioner,把相同域名的访问次数做合并是一个比较经典的应用,hash(hostname(URL)) mod R确保相同域 名的网页交给同一个Reduce Task处理。

Reducer从Mapper读取数据到本地进行排序汇总。把相同key的value聚合到一起,最后形成Outputformat输出。

Mapper的数量由数据集拆分的数量决定,可以10个文件用一个Mapper,也可以1个文件被10个Mapper处理,也可以由用户指定,Reducer的数量由用户指定。

在这里插入图片描述Map的结果发送到不同的Reduce节点,由于有多个Mapper和多个Reducer,所以要把对应的子任务放到对应的Reducer,这个过程叫做Shuffling。Shuffling决定将某些数据发送到某个Reducer,相同的单词交个同一个Reducer处理,或者将某个单词哈希后决定给哪个Reducer,Shuffling把相同的单词放一起。Map和Reduce的计算是各自独立互不影响。Reduce包含Shuffling,Shuffling是为Reduce准备数据。一般用key哈希然后取模后分配给某个Reducer。
Final Result是一个逻辑结果,不一定在一个物理机器上,也不一定非要合并到一个物理机器上。
在这里插入图片描述
输入为一系列key/value对,MapReduce提供两个函数Map(k,v) -> k1,v1和Reduce(k1, list(v1)) -> k2, v2 ,(k1,v1) 是中间key/value结果对,输出为一系列(k2,v2)对。

伪代码:
Map(key, value):
// key: line offset; value: line
for each word w in value:
emit(w, 1)
Reduce(key, values):
// key: a word; values: an iterator over counts
result = 0
for each count v in values:
result += v
emit(key,result)

MapReduce内部逻辑
在这里插入图片描述1)文件分片成Split;
2)Inputformat把文件转化为key,value对交给Mapper处理,由Mapper将key,value对转化为中间的key,value对;
3)中间的key,value对由Partitioner决定它们分别属于哪个分区,Mapper将所有属于同一个Reducer的key都聚合到了同一个分区;
4)Shuffle从Mapper取到属于自己分区的数据按照key做排序得到一个有序的key,value对,这些数据为Reducer消费;
5)Reducer调用用户编写的模型数据输出key,value对;
6)最后由Outputformat将结果写到HDFS对应的位置。
如果一个key的value非常多的情况下,可能会出现数据倾斜,然后一个Reducer不停的跑,其他的Reducer比较闲,需要仔细设置key。这里是简化模型,通常情况下一个Reducer会处理多个key。

MapReduce架构

在这里插入图片描述上图蓝色部分是Yarn(资源管理器:管理调度整个集群的计算资源),黄色部分是MapReduce。

HDFS管理集群存储(磁盘),包括:
1)NameNode管理元信息,存储文件数量,文件ID,文件包括哪些Block,每个Block在哪个节点(Hadoop上的一台机器),它记录哪个节点比较空余;
2)DataNode部署在每个节点上,存储文件实际数据;
NameNode和DataNode是一种Master和Slave的关系;

Yarn管理计算资源(CPU和内存),做计算,包括:
1)ResourceManager记录计算元信息,管理计算资源,相当于NameNode,包括集群里有节点数量,每个节点CPU数量和内存数量以及节点空闲的CPU和内存数量,
2)NodeManager存储计算资源,真正执行计算任务,相当于DataNode,每个节点上都安装有NodeManager,记录当前节点的资源数量以及闲置资源数量。Client向ResourceManger请求4个CPU和8G内存的计算资源,批准后NodeMananger就启动一个进程Container,RecourceManager就会减去这个计算资源。
一般Resource Manage单独部署,Namenode、Datanode、ResourceManager和NodeManager之间没有强关联关系,可以放在一个节点上。Yarn是一个资源管理和调度的框架,可以运行MapReduce、Spark或是Storm等多个计算框架或计算引擎。这个框架需要各个Task分布协调运行,各个Task加起来是一个计算框架(计算引擎)。

用户通过Client与Yarn交互,提交MapReduce作业,查询作业运行状态,管理作业等。MapReduce是多进程程序,Client发出请求后,启动一个Application Master的进程Container,驱动Map Task(Application Master计算需要运行多少Map Task来处理所有的分片)和Reduce Task(用户输入Reduce Task的数量,如果不指定,默认1个),Application Master记录Map Task和Reduce Task的数量。每个Map Task和Reduce Task需要一个进程Container,Application Master按照每个Map Task和Reduce Task需要的CPU和内存数量计算运行Mapreduce所需要的计算资源。Applicatoin Master向Resource Manager请求计算资源后,再向NodeManager请求对应的Container来运行Map Task和Reduce Task。Application Master可以在任意一个节点上运行。运行Application Master的Container只是一个普通的进程,与Map Task和Reduce Task分别运行不同的程序,Application Master管理自己的Task。如果同时提交了两个MapReduce,会启动两个Application Master,各自管理自己的Task。

早期的Yarn包括JobTracker和TaskTracker,分别对应ResourceManager和NodeManager,JobTracker既要负责资源的管理和调度,又要负责任务的管理和调度,任务比较重。新版本的Yarn,资源(需要多少CPU、内存等资源)的管理和调度有ResourceManager负责,任务(任务划分,包括需要启动多少个Map Task和多少个Reduce Task,分别需要在哪些机器上执行以及任务状态监控和容错)的管理和调度由ApplicationMaster负责,它负责向ResouceManager申请资源分配给Map Task或Reduce Task,如果发现有错误再次调度。

Spark、Storm等也都是运行在Yarn上,Application Master不仅负责MapReduce的任务,也要负责Spark、Storm的任务。

在这里插入图片描述
1)Client将请求数据(包括从哪读数据,数据写到哪里,需要多少个CPU才能运行Task)传递给ResourceManager(存储了NodeManager的数量以及每个NodeManager上空余CPU和空余内存的数量);
2)ResourceManagerr找到匹配的空余资源后,启动MapReduce的ApplicationMaster的进程;
3)ApplicationMaster向ResourceManager申请CPU和内存等资源来运行Map Task和Reduce Task;
4)ApplicationMaster得到资源后,会启动多个Container运行Map Task和Reduce Task;
5)如果有Map Task或Reduce Task运行完毕告诉ApplicationMaster关掉这个进程,等所有程序都运行完了,ApplicationMaster会把数据迁移到特定的目录。

Client可以通过ResourceManager查看ApplicationMaster的状态,以及各个Task的状态。

MapReduce容错性

  • MRAppMaster容错性
    一旦运行失败,由Yarn的ResourceManager负责重新启动 ,最多重启次数可由用户设置,默认是2次。
    AppMaster停掉后,之前它管理的Map Task和Reduce Task也会停掉,因为NodeManager会每隔一秒向ResourceManager汇报它管理的进程,ResourceManager一旦发现这些Task属于的AppMaster已经停掉,就会杀死这些僵尸进程。

  • Map Task/Reduce Task
    Task周期性向MRAppMaster汇报心跳,一旦Task挂掉,则MRAppMaster将为之重新申请资源并运行。最多重启次数可由用户设置,默认4次。

    如果是因为网路问题,是应该重启的,但如果是因为程序的问题,就不应该被重启了,所以超过设置的启动次数后就不会再被重启了,此时作业运行失败。

MapReduce数据本地性
如果任务运行在它将处理的数据所在的节点,则称该任务具有“数据本地性(Data Locality)”,本地性可避免跨节点或机架数据传输,提高运行效率。数据本地性分为:
1)同节点(Node-Local):计算节点和数据节点在同一个节点上;
2)同机架(Rack-Local) :计算节点和数据节点在同一个机架上;
3)其他(Off-Switch)。
这主要标识数据吞吐量的大小,在一个节点数据吞吐量最大,跨交换机数据吞吐量就会减小。

在这里插入图片描述Application Master获取数据源信息,包括文件路径、文件数量、Splite数量以及对应启动的Task数量,比如要启用4个Map Task,Application Master需要了解这四个Map Task的数据存放的DataNode。Application Master向ResourceManager请求计算资源,由NodeManager通知Application Master空闲计算节点,Application Master分配Task到空闲计算节点,数据源所在节点和Task运行的计算节点如果相同就符合数据本地性。
在这里插入图片描述Task1读取b1的时候属于同节点本地读取,Task2读取b2的时候,因为H5和H3的计算资源已经没了,就选择H4,这样就是跨节点、跨机架读取数据了。
1个Splite默认是和一个File的一个Block对应的。比如一个File有b1、b2、b3、b4四个Block,每个Block是128M,如果设置一个Splite要处理256M的数据,这个Splite包含两个Block,如果这两个Block不在同一个节点上,所以至少一个Block需要跨网路去取数据,这样就造成了数据的非本地性,数据网路产生。

MapReduce推测执行机制
MapReduce作业完成时间取决于最慢的任务完成时间,一个作业由若干个Map Task和Reduce Task构成,因硬件老化、软件Bug等,某些Task可能运行非常慢。MapReduce发现拖后腿的任务,比如某个任务运行速度远慢于任务平均速度,就为拖后腿任务启动一个备份任务,同时运行,谁先运行完,则采用谁的结果,这既是推测执行机制。但是当任务间存在严重的负载倾斜,或者一些特殊任务,比如向数据库中写数据,不能启用推测执行机制。负载倾斜的时候用推测执行,不会有太多的作用;写数据的任务不能用推测执行,是因为容易出现重复写数据的问题。
MapReduce任务并行执行
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/fegang2002/article/details/86146481
今日推荐