Hadoop必知必会(HDFS+MapReduce部分)

GalbraithFay 发布于1年前

Hadoop是一个分布式存储和并行计算综合的系统。分布式存储由HDFS,HBase,Hive等实现,并行计算由MapReduce计算框架实现。

也就是说,Hadoop系统主要分为分布式存储和并行计算部分。集群中一般有一个主控节点,和若干个从节点。分布式存储方面,主控节点维护一个NameNode,存储文件元数据信息,从节点各维护一个DataNode,存储具体的数据。并行计算方面,主控节点维护一个JobTracker守护进程,负责管理和调度任务,从节点各维护一个TaskTracker,负责拉取任务和执行具体的任务。并行计算方面目前广泛采用YARN来管理任务调度,在YARN中,JobTracker的职能由ResourceManager承担,TaskTracker的职能由NodeManager承担。

具体的,YARN中还有ApplicationMaster和Container等概念。

MapReduce

MapReduce是Hadoop的并行计算部分。MapReduce是一种并行计算的框架和编程模式,提供任务调度,数据和任务互定位,系统优化和容错,提供一套大数据编程接口。

主要参考了Lisp的map/reduce原语设计思想,提供了两个主要的编程接口:Map和Reduce。Map指的是针对不同数据进行同一种操作。Reduce主要是对Map的中间结果进行某种进一步的整理和输出。

MapReduce的数据表示一般为key-value,Map,Reduce函数都是对key-value对来操作。

Map的功能逻辑主要是对输入key-value进行一些处理,产生新的key-value对。

每个map对分别对划分的部分数据进行处理,多个map并行处理。

Reduce的功能逻辑主要是对map输出的每组(key, values)进行整理和计算,最后产生新的key-value对。

为了解决两个问题,MapReduce框架还提供了另外两个类来增强MapReduce的能力。

问题1:多个重复的key发到网络上进行shuffle,带来许多不必要的传输。

解决方案:Combiner会在本地先进行相同key的合并,保证最后不会有重复的key。

问题2:如果不进行恰当的分区,可能会出现同一个key被划分到不同的reduce节点,造成数据的相关性,从而无法产生正确的统计。

解决方案:Partitioner会对中间结果key-value进行恰当的分区处理,使得reduce节点分到的数据一定互不相关。

Combiner作用在Map完成计算之后,输出结果之前。

Partitioner作用在Map输出结果之后,发送到Reduce节点之前。

一般来说,添加了Combiner和Partitioner的MapReduce模型才是完整的。

完整的MapReduce计算框图见《深入理解大数据》P96。

MapReduce实现计算向数据迁移的方式:

优先调度那些输入数据在本地节点的Map任务到本地节点。

具体的,JobScheduler维护了许多Java Map数据结构,存储任务和任务输入数据所在节点。

如果数据A存在于node1,node2,node3上,三个副本,A又是任务T的输入,那么node1,node2,node3这三个节点的可分配任务集中都会包含A。

MapReduce有三种调度方法:

1)FIFO先进先出调度。

2)公平调度,公平调度又实现了两级延迟调度,即如果不能调度到本地节点,则进行一段时间的等待,如果还没有则准备调度到rack机器上,如果rack机器也不闲,那么又稍微等一下,如果实在是大家都没空,只有调度到本机架外的任意机器上了。

3)计算能力调度,考虑内存等资源能否满足的调度方式。

MapReduce主要组件和编程接口

主要组件有InputFormat,描述了MapReduce作业的输入格式。

有三个任务:

1)验证输入形式和格式

2)将输入数据分割成若干逻辑意义上的InputSplit,每个InputSplit都是一个Mapper的输入

3)提供RecordReader,将Mapper的输入(InputSplit)处理转化为若干输入记录(key-value对)

InputFormat确定了,那么InputSplit和RecordReader的类型也都确定了。

事实上作业的Mapper数量是由InputSplit数量决定的。

map函数中有一个context,表示的是环境对象参数,供程序访问Hadoop的环境对象。

Mapper输出前,系统会默认提供一个Combiner对输出结果进行合并,以免造成不必要的网络传输。当然也可以自己定义。但是要注意,Combiner不能改变Mapper输出的键值对的数据类型,否则用于不用Combiner的结果不再一致。有时可以直接拿Reducer当Combiner用。

Mapper输出后,系统也会默认提供一个Partitioner对输出结果进行分组,确保同一key的数据分到同一个Reduce节点。

实际执行时,Combiner实在Map节点上执行的,而Partitioner和Sort实在Reduce节点上执行的。

Sort是一个容易被忽略的过程,在Mapper产生的中间结果发送到Reducer之前,系统会对中间结果(表现为本地磁盘的一个或多个文件)每个文件进行快速排序,然后对这些文件进行归并排序,合并成一个大文件。

HDFS

HDFS启动,NameNode进入安全模式,检查DataNode上的数据块,如果安全的数据块比例达到要求,则退出安全模式,正式启动了HDFS。

NameNode容错通过SecondaryNameNode的备份来实现。主要通过文件镜像FsImage和编辑日志EditLog来实现检查点Checkpoint机制。

fsImage和edits.log会周期性的进行合并,由SecondaryNameNode来完成,为NameNode减轻压力。

过程如下:

secondary namenode请求主Namenode停止使用edits文件,暂时将新的写操作记录到一个新文件中,如edits.new。 
secondary namenode节点从主Namenode节点获取fsimage和edits文件(采用HTTP GET) 
secondary namenode将fsimage文件载入到内存,逐一执行edits文件中的操作,创建新的fsimage文件
secondary namenode将新的fsimage文件发送回主Namenode(使用HTTP POST) 
主Namenode节点将从secondary namenode节点接收的fsimage文件替换旧的fsimage文件,用步骤1产生的edits.new文件替换旧的edits文件(即改名)。同时更新fstime文件来记录检查点执行的时间

FQA

  • Hadoop的各角色的职能?

集群观点上的角色?还是整个Hadoop系统上各个组件观点上的角色?

集群观点上,JobTracker, TaskTracker, NameNode, DataNode等的职能如上节所见。

系统观点上,HBase,Hive,YARN,MapReduce,HDFS等各司职要也已简要说明。

  • Hadoop的Checkpoint的作用?

保证容错,保证NameNode挂掉后能够从比较近的检查点恢复。

具体容错过程见上节。

  • Hadoop数据块为什么要设置64MB或者更大?

减少寻址开销,因为每次寻址都要经过NameNode -> DataNode,然后交换数据。

  • Hadoop的高可靠性如何保证?

Hadoop主要包含两个部分,HDFS和MapReduce。

HDFS方面,又包含两种节点,NameNode和DataNode。

为了保证NameNode的可靠性,HDFS采取了SecondaryNameNode来备份元数据,并周期性的设置 检查点 的方式。

为了保证DataNode挂掉,数据访问的可靠性,HDFS采取了 多副本 数据存储,保证单节点挂掉不影响数据的获取。

整体方面,采取了 心跳机制 来保证互相通信和失效节点及时检测,并实现了 副本重新创建 机制。

文件访问采取 租约 机制。

数据一致性采取 校验和 机制。

以及采取了 版本回滚 策略。

MapReduce方面,TaskTracker会周期性的向JobTracker发送 心跳 信息,JobTracker能够及时检测TaskTracker的失效。

JobTracker的可靠性问题可以依靠 Zookeeper 来优化。

采用YARN能够更好地保证MapReduce框架的可靠性。

  • MapReduce中的Text类型和LongWritable类型能不能用String 或者用long类型代替?

不能,InputFormat一旦确定,其Mapper的输入格式也就确定了,不能改为其他类型。Text和String虽然很像,但是Text是针对于UTF-8的writable类型,String采用的是Java Char,二者并不一致。

  • MapReduce常用的接口?

InputFormat, OutputFormat, RecordReader, RecordWriter, Mapper, Reducer, map, reduce, Combiner, Sorter, Partitioner等。

  • MapReduce的工作流程?

InputFormat将输入数据读入,验证输入数据的形式和格式,将数据分割为InputSplit,用RecordReader将InputSplit转化为一条条的记录(Key-value对)。

Mapper以各自的InputSplit作为输入,map函数对InputSplit中的记录(key-value)逐个处理,生成新的key-value对,然后由Combiner将这些key-value对进行整理,将相同key的values合并,变成一个key-value,然后输出中间结果到磁盘,中间结果经过Partitioner的分组,被发送到合适的Reduce节点上,传入Reducer之前还会自动将所有key-value按照key值排序,然后结果进入Reducer,reduce函数对(key, values)进行计算以后,经过OutputFormat对象指定输出的格式,将数据写回HDFS中。

  • MapReduce优化方式?

对Reduce节点个数进行优化。

将负载重的工作尽量使用多个Reduce节点来做,适当分割阶段,但是阶段不要分割太多,否则有多次磁盘开销,权衡下尽量减少不必要的阶段拆分。

尽量压缩数据结构,能用IntWritable就不用LongWritable。

适当使用变长IntWritable(VIntWritable)和变长LongWritable(VLongWritable),变长xxWritable可以根据实际数值决定存储的位数,在数字分布不均匀的情况下推荐用变长的Writable。

总的来说就是三点:

1)Reduce节点个数

2)阶段

3)数据结构

  • 什么样的情况下不能用MapReduce?

1)无法表示成key-value的数据,无法将操作分解为map,reduce两个操作的

2)不是操作相同,处理数据不同,而是数据间有相关的应用

3)多次迭代的任务不适合用MapReduce

  • HDFS的架构?

包含一个主控节点NameNode和一组DataNode从节点。

NameNode管理整个文件系统的元数据和命名空间,并负责相应外部访问请求。

DataNode负责具体数据块的存储,负责具体的数据读写请求,创建删除数据块等。

  • HDFS优化?

1)尽可能使用二进制的Writable类型,减小存储空间

2)副本数

3)块大小

等等【可补充】

查看原文: Hadoop必知必会(HDFS+MapReduce部分)

  • organicgoose
  • blueswan
  • ticklishostrich
  • goldenmouse
  • ticklishmeercat
  • biggoose
  • beautifulmouse
  • bigfrog
  • silvergorilla