hadoop 笔记

http://www.aboutyun.com/thread-7778-1-1.html


obTracker和TaskTracker

JobTracker  对应于 NameNode

TaskTracker 对应于 DataNode

DataNode 和NameNode 是针对数据存放来而言的

JobTracker和TaskTracker是对于MapReduce执行而言的

 

mapreduce中几个主要概念,mapreduce整体上可以分为这么几条执行线索:

jobclient,JobTracker与TaskTracker。

1、JobClient会在用户端通过JobClient类将应用已经配置参数打包成jar文件存储到hdfs,

并把路径提交到Jobtracker,然后由JobTracker创建每一个Task(即MapTask和ReduceTask)

并将它们分发到各个TaskTracker服务中去执行

2、JobTracker是一个master服务,软件启动之后JobTracker接收Job,负责调度Job的每一个子任务task运行于TaskTracker上,

并监控它们,如果发现有失败的task就重新运行它。一般情况应该把JobTracker部署在单独的机器上。

3、TaskTracker是运行在多个节点上的slaver服务。TaskTracker主动与JobTracker通信,接收作业,并负责直接执行每一个任务。

TaskTracker都需要运行在HDFS的DataNode上 这样利于本地化计算 。

Hadoop在存储有输入数据(HDFS中的数据)的节点运行map任务,可以获得最佳性能。这就使所谓的数据本地化优化。

jobtracker 利用 split的 location 数组 来决定 这个task 运行在哪个tasktracker上 。而 这个task的输入数据最好存在location数组中 这样 task就可以读本地的数据 。 


map任务将其输入写入本地硬盘,而非HDFS。因为map的输出是中间结果:该中间结果由reduce任务处理后才产生最终输出结果。

 

6.Hadoop0.20.0包含新的Java MapReduce API,与旧的API的区别:

6.1新的API倾向于使用虚类,而不是接口,因为这更容易扩展。mapper和reducer都是虚类

6.2 新的API放在org.apache.hadoop.mapreduce包中

6.3 新的API使用MapContext上下文对象,使用户代码能与MapReduce系统通信。MapContext基本具备了JobConf,OutputCollector和Reporter功能

6.4 新的API支持“推”和“拉”式的迭代。

6.5 新的API实现了配置的统一。所有作业的配置均通过Configuration来完成。

6.6 新的API中作业控制由Job类实现,删除了JobClient类

6.7 输出文件的命名方式稍有不同,map的输出文件名为part-m-nnnnn,而reduce的输出为part-r-nnnnn(其中,nnnnn表示分块序号,为整数,且从0开始)

MapReduce作业是客户端需要执行的一个工作单元,包括:输入数据、MapReduce程序和配置信息。

有2类节点控制着作业执行过程:一个jobtracker和一系列tasktracker

jobtracker通过调度tasktracker上运行的任务,来协调所有运行在系统上的作业;tasktracker在运行任务的同时,将运行进度报告发送给jobtracker,jobtracker由此记录每项作业任务的整体进度情况。如果其中一个任务失败,jobtracker可以在另一个tasktracker节点上重新调度该任务。


reduce任务并不具备数据本地化的优势,单个reduce任务的输入通常来自于所有的mapper的输出,因此,排序后的map输出需通过网络传输发送到运行reduce任务的节点。数据在reduce端合并,然后由用户定义的reduce函数处理,reduce的输出通常存储在HDFS中以实现可靠存储。因此,reduce输出写入HDFS确实需要占用网络带宽。


也可能没有任何reduce任务,数据处理可以完全并行时,即无需混洗,此时,唯一的非本地节点数据传输是map任务将结果写入HDFS。 daily merge 就是如此  怎么做到的呢 metafile?


 集群上的可用带宽限制了MapReduce作业的数量,因此最重要的一点是尽量避免map任务和reduce任务之间的数据传输。因此,Hadoop允许用户针对map任务的输出指定一个合并函数



http://blog.csdn.net/lskyne/article/details/8841176


jobClient向HDFS提交的资源就包含了InputSplit,这就是数据划分的结果。也就是说,数据划分是在JobClient上完成的。在这里,JobClient会使用指定的InputFormat将输入数据做一次划分,形成若干个Split。
因为关于Split的那些描述信息,对于MapReduce框架来说是不需要关心的。框架只关心Split的长度(主要用于一些统计信息)和Split的Location(主要用于Split的调度,后面会细说)。


而Split中真正重要的描述信息还是只有InputFormat会关心



FileInputFormat默认为文件在HDFS上的每一个Block生成一个对应的FileSplit。那么自然,FileSplit.start就是对应Block在文件中的Offset、FileSplit.length就是对应Block的Length、FileSplit.hosts就是对应Block的Location。
但是可以设置“mapred.min.split.size”参数,使得Split的大小大于一个Block,这时候FileInputFormat会将连续的 (逻辑上连续的)若干个Block分在一个Split中、也可能会将一个Block分别划在不同的Split中(但是前提是一个Split必须在一个文件中)。Split的Start、Length都好说,都是划分前就定好的。而Split的Location就需要对所有划在其中的Block的Location进行整合,尽量寻找它们共有的Location。而这些Block很可能并没有共同的Location,那么就需要找一个距离这些Block最近的Location作为Split的Location。 --- 但是好像看源码 没有整合 直接取 开始位置的块的hosts



 private Path[] paths;       // 每个子Split对应一个文件
  private long[] startoffset; // 每个子Split在对应文件中的起始位置
  private long[] lengths;     // 每个子Split的长度
  private String[] locations; // Split所在的机器名称,getLocations()会返回它
  private long totLength;     // 所有子Split长度之和,getLength()会返回它
其中前三个数组一定是长度相等并且一一对应的,描述了每一个子Split的信息。而locations,注意它并没有描述每一个子Split,而描述的是整个Split。这是因为CombineFileInputFormat在打包一组子Split时,会考虑子Split的Location,尽量将在同一个Location(或者临近位置)出现的Split打包在一起,生成一个CombineFileSplit。而打包以后的locations自然就是由所有子Split的Location整合而来。
同样,配套使用的RecordReader将从CombineFileSplit中获取信息,解析每一个文件名为CombineFileSplit.paths[i]的文件中从CombineFileSplit.startoffset[i]到CombineFileSplit.startoffset[i]+CombineFileSplit.lengths[i]之间的内容。



前面在划分输入数据的时候,不断提到Location这个东西。InputSplit接口中有getLocations()、InputFormat的implement在生成InputSplit的时候需要关心对应Block的Location,并且当多个Block需要放到一个InputSplit的时候还需要对Location做合并。
那么这个Location到底用来做什么呢?它主要就是用来给Split的调度提供参考。


在分配Map任务时,Split的Location信息就要发挥作用了。JobTracker会根据TaskTracker的地址来选择一个Location与之最接近的Split所对应的Map任务(注意一个Split可以有多个Location)。这样一来,输入文件中Block的Location信息经过一系列的整合(by InputFormat)和传递,最终就影响到了Map任务的分配。其结果是Map任务倾向于处理存放在本地的数据,以保证效率。



咋一看,RecordReader似乎会使用Split的Location信息来决定数据应该从哪里去读。但是事实并非如此。前面也说过,Split的Location很可能是被InputFormat整合过的,可能并不是Block真正的Location(就算是,也没法保证从InputSplit在JobClient上被生成到现在的这段时间之内,Block没有被移动过)。
说白了,Split的Location其实是InputFormat期望这个Split被处理的Location,它完全可以跟实际Block的Location没有半点关系。InputFormat甚至可以将Split的Location定义为“距离Split所包含的所有Block的Location最远的那个Location”,只不过大多数时候我们肯定是希望Map程序在本地就能读取到输入数据的。

所以说,RecordReader并不关心Split的Location,只管Open它的Path。


RecordReader对一个Path的Open操作由DFSClient来完成,它会向HDFS的NameNode获取对应文件在对应区间上的Block信息:依次有哪些Block、每个Block各自的Location。而要读写一个Block的时候,DFSClient总是使用NameNode返回的第一个Location,除非读写失败才会依次选择后面的Location。
而NameNode在处理Open请求时(getBlockLocations),在得到一个Block有哪些Location之后,会以DFSClient所在的地址为依据,对这些Location进行排序,距离越小的越排在前。而DFSClient又总是会选择排在前面的Location,所以,最终RecordReader会倾向于读取本地的数据(如果有的话)。

但是,不管Block是不是本地的,DFSClient都会向DataNode建立连接,然后请求数据。并不会因为Block是本地的而直接读磁盘上的文件,因为这些文件都是由DataNode来管理的,需要通过DataNode来找到Block所对应的物理文件、也需要由DataNode来协调对文件的并发读写。所以本地与非本地的差别仅仅在于网络传输上,前者是仅仅在本地网络协议栈上面绕一圈、而后者则是真正的网络通讯。在Block离得不远、且网络比较畅通的情况下,非Local并不意味着太大的开销。


你可能感兴趣的:(hadoop 笔记)