目录
前言
core-site.xml
hdfs-site.xml
mapred-site.xml
yarn-site.xml
一、HDFS
HDFS的设计理念
HDFS的缺点
1、NameNode
1.1、namenode的作用
1.2、元数据目录说明
1.3、NameNode启动
2、Secondary NameNode
3、数据存储细节
4、DataNode
5、Blocks块(最小化寻址,加快数据传输速度)
6、HDFS文件读取的解析
7、HDFS文件写入的解析
8、HDFS通信协议
9、HDFS的安全模式
10、副本机制
11、HDFS负载均衡
12、HDFS机架感知
13、HDFS访问方式
14、HDFS 健壮性;数据出错与恢复
15、快照
16、HDFS 文件删除恢复机制
17、HDFS 分布式缓存(DistributedCache )
18、HDFS Fedoration机制
19、HDFS High-Availabilty
20、 常见问题分析
二、MapReduce
1、MapReduce原理
1.1、Map阶段
1.2、Reduce阶段
三、yarn
前言
Hadoop几个重要的配置文件
core-site.xml是全局配置,hdfs-site.xml和mapred-site.xml分别是hdfs和mapred的局部配置。
core-site.xml
<configuration>
<!--指定namenode的地址-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://master:9000</value>
</property>
<!--用来指定使用hadoop时产生文件的存放目录-->
<property>
<name>hadoop.tmp.dir</name>
<value>file:///usr/hadoop/hadoop-2.6.0/tmp</value>
</property>
这里有2个参数可配置,但一般来说我们不做修改。fs.checkpoint.period表示多长时间记录一次hdfs的镜像。默认是1小时。fs.checkpoint.size表示一次记录多大的size,默认64M。
<property>
<name>fs.checkpoint.period</name>
<value>3600</value>
<description>The number of seconds between two periodic checkpoints. </description>
</property>
<property>
<name>fs.checkpoint.size</name>
<value>67108864</value>
<description>The size of the current edit log (in bytes) that triggers a periodic checkpoint even if the fs.checkpoint.period hasn't expired. </description>
</property>
</configuration>
hdfs-site.xml
涉及到HDFS到几个重要配置
1. dfs.name.dir
/usr/hadoop/hdfs/name
存贮在本地的名字节点数据镜象的目录,作为名字节点的冗余备份
2. dfs.data.dir
/usr/hadoop/hdfs/data
数据节点的块本地存放目录
3. dfs.replication
3
缺省的块复制数量
4. dfs.webhdfs.enabled
true
使WebHDFS(REST API)在Namenodes和数据节点。
5. dfs.namenode.secondary.http-address
centos201:9001
Namenode HTTP服务器地址和端口。
mapred-site.xml
<configuration>
<!--告诉hadoop以后MR(Map/Reduce)运行在YARN上-->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<!--nodeManager获取数据的方式是shuffle-->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!--指定Yarn的老大(ResourceManager)的地址-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>master</value>
</property>
<!--Yarn打印工作日志-->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<configuration>
一、HDFS
HDFS集群分为两大角色: NameNode、DataNode
NameNode:是Master节点,负责管理整个文件系统的元数据。管理数据块映射;处理客户端的读写请求;配置副本策略;管理HDFS的名称空间;
SecondaryNameNode:是一个小弟,分担大哥namenode的工作量;是NameNode的冷备份;合并fsimage和fsedits然后再发给namenode。SecondaryNameNode负责定时默认1小时,从namenode上,获取fsimage和edits来进行合并,然后再发送给namenode。减少namenode的工作量。
DataNode:Slave节点,负责管理用户的文件数据块.奴隶,干活的。负责存储client发来的数据块block;执行数据块的读写操作。
热备份:b是a的热备份,如果a坏掉。那么b马上运行代替a的工作。
冷备份:b是a的冷备份,如果a坏掉。那么b不能马上代替a工作。但是b上存储a的一些信息,减少a坏掉之后的损失。
fsimage:元数据镜像文件(文件系统的目录树。)
edits:元数据的操作日志(针对文件系统做的修改操作记录)
namenode内存中存储的是=fsimage+edits。
文件会按照固定的大小(blocksize)切成若干块后分布式存储在若干台DataNode上。每一个文件块可以有多个副本,并存放在不同的DataNode上。
DataNode会定期向NameNode汇报自身所保存的文件block信息,而NameNode则会负责保存文件的副本数量。
HDFS的内部工作机制对客户端保持透明,客户端请求访问HDFS都是通过NameNode申请来进行。
我们通过hadoop shell上传的文件是存放在DataNode的block中,通过linux shell是看不到文件的,只能看到block。可以一句话描述HDFS:把客户端的大文件存放在很多节点的数据块中。在这里,出现了三个关键词:文件、节点、数据块
HDFS采用master/slave架构。一个HDFS集群是由一个NameNode和一定数目的DataNodes组成。NameNode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的DataNode一般是一个节点一个,负责管理它所在节点上的存储。HDFS暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组DataNode上。NameNode执行文件系统的名字空间操作,例如打开、关闭、重命名文件或目录。它也负责确定数据块到具体DataNode节点的映射。DataNode负责处理文件系统客户端的读写请求。在NameNode的统一调度下进行数据块的创建、删除和复制。
hdfs的特点:适用于一次写入、多次查询的情况,不支持并发写情况,小文件不合适。因为小文件也占用一个块,小文件越多(1000个1k文件)块越多,NameNode压力越大。
HDFS的设计理念
1、存储超大文件
这里的“超大文件”是指几百MB、GB甚至TB级别的文件。
2、流式数据访问
HDFS是建立在最有效的数据处理模式是一次写多次读(write-once,read-many-times)的模式的概念之上的,HDFS存储的数据集作为hadoop的分析对象。
在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
(流式读取最小化了硬盘的寻址开销,只需要寻址一次,然后就一直读啊读。硬盘的物理构造导致寻址开销的优化跟不上读取开销。所以流式读取更加适合硬盘的本身特性。
当然大文件的特点也更适合流式读取。与流数据访问对应的是随机数据访问,它要求定位、查询或修改数据的延迟较小,比较适合于创建数据后再多次读写的情况,传统关系型数据库很符合这一点)
1.3、运行在普通廉价的服务器上HDFS设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。
HDFS的缺点
1、将HDFS用于对数据访问要求低延迟的场景
由于HDFS是为高数据吞吐量应用而设计的,必然以高延迟为代价。
2、存储大量小文件
HDFS中元数据(文件的基本信息)存储在namenode的内存中,而namenode为单点,小文件数量大到一定程度,namenode内存就吃不消了。 因为 Namenode 把文件系统的元数据放置在内存中,所以文件系统所能 容纳的文件数目是由 Namenode 的内存大小来决定。一般来说,每一个文件 、文件夹和 Block 需要占据 150 字节左右的空间,所以,如果你有 100 万个文 件,每一个占据一个 Block ,你就至少需要 300MB 内存。当前来说,数百万 的文件还是可行的,当扩展到数十亿时,对于当前的硬件水平来说就没法实 现了。还有一个问题就是,因为 Map task 的数量是由 splits 来决定的,所以 用 MR 处理大量的小文件时,就会产生过多的 Maptask ,线程管理开销将会 增加作业时间。举个例子,处理 10000M 的文件,若每个 split 为 1M ,那就会 有 10000 个 Maptasks ,会有很大的线程开销;若每个 split 为 100M ,则只有 100 个 Maptasks ,每个 Maptask 将会有更多的事情做,而线程的管理开销也 将减小很多。
HDFS架构图HDFS数据上传原理可以参考图2-5对照理解,数据上传过程如下所示:
1)Client端发送一个添加文件到HDFS的请求给NameNode;
2)NameNode告诉Client端如何来分发数据块以及分发的位置;
3)Client端把数据分为块(block),然后把这些块分发到DataNode中;
4)DataNode在NameNode的指导下复制这些块,保持冗余。
1、NameNode
1.1、namenode的作用
NameNode的作用是管理文件目录结构,接受用户的操作请求,管理数据节点。名字节点维护两套数据关系:
1.1.1、文件与数据块之间的关系。是静态的,存放在磁盘上的,通过fsimage和editslog文件来维护。
1.1.2、数据块与节点之间的关系。不持久放到到磁盘,每当集群启动的时候,datanode节点会向namenode节点汇报自己管理的数据块有哪些,会自动建立这些信息,所以一般都放在内存中。
所以他是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表,接收用户的操作请求。文件包括:
fsimage(文件系统镜像):元数据镜像文件。存储某一时段NameNode内存元数据信息。
edits:操作日志文件。
以上这些文件是保存在linux的文件系统中
HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目 录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数 现有的文件系统类似:用户可以创建、删除、移动或重命名文件。当前, HDFS 不支持用户磁盘配额和访问权限控制,也不支持硬链接和软链接。但 是 HDFS 架构并不妨碍实现这些特性。 Namenode 负责维护文件系统命名空间,任何对文件系统名字空间或属 性的修改都将被 Namenode 记录下来。应用程序可以设置 HDFS 保存的文件 的副本数目。文件副本的数目称为文件的副本系数,这个信息也是由 Namenode 保存的。
Namenode 上保存着 HDFS 的名字空间。对于任何对文件系统元数据产生修改的操作, Namenode 都会使用一种称为 EditLog 的事务日志记录下来。例如,在 HDFS 中创建一个文件, Namenode 就会在 Editlog 中插入一条记录来表示;同样地,修改文件的副本系数也将往 Editlog 插入一条记录。 Namenode 在本地操作系统的文件系统中存储这个 Editlog 。整个文件系统的名字空间,包括数据块到文件的映射、文件的属性等,都存储在一个称为 FsImage 的文件中,这 个文件也是放在 Namenode 所在的本地文件系统上。 Namenode 在内存中保存着整个文件系统的名字空间和文件数据块映射 (Blockmap) 的映像 。这个关键的元数据结构设计得很紧凑,因而一个有 4G 内存的 Namenode 足够支撑大量的文件 和目录。当 Namenode 启动时,它从硬盘中读取 Editlog 和 FsImage ,将所有 Editlog 中的事务作 用在内存中的 FsImage 上,并将这个新版本的 FsImage 从内存中保存到本地磁盘上,然后删除 旧的 Editlog ,因为这个旧的 Editlog 的事务都已经作用在 FsImage 上了。这个过程称为一个检查 点 (checkpoint) 。在当前实现中,检查点只发生在 Namenode 启动时,在不久的将来将实现支持周期性的检查点。
namenode是整个分布式文件系统的一个单点故障(single point of failure),没有了namenode整个分布式文件系统就无法使用了,因为我们无法从blocks中重构出相应的文件了。所以确保namenode能从失败中及时恢复是很重要的一件事,我们可以从以下两方面入手:
1. 第一种方法就是备份namenode中保存的永久信息(也就是上文中所提到的namespace image和edit log),namenode可以经过额外配置把它的永久信息保存到多个文件系统上去(这些多写操作是同步和原子性的)。最常用的做法是把永久信息保存到本地文件系统和某个远程NFS(Network FileSystem)上去。
2. 另一种可能的做法就是运行一个secondary namenode,尽管它的名字跟namenode听起来差不多,但它的功能跟namenode却不一样。它最主要的工作就是把namespace image检查点文件与edit log相融合(以防止edit log过大)并把融合后的namespace image保存在自己的本地文件系统上,同时发送这个新的备份给namenode。因为需要大量CPU资源和跟namenode一样大小内存的缘故, secondary namenode通常运行在另一个单独的机器上(关于更多secondary namenode运行的描述请参看这里)。然后由于secondary namenode上保存的状态信息总是要滞后于namenode上的状态信息的缘故(未融合的edit log记录了这一部分改变),如果namenode完全失败,数据肯定要丢失一部分。
通常的做法是把上述两种方法结合起来,也即当namenode当机时,把远端NFS上的namespace image拷贝到secondary namenode上,然后把secondary namenode当做namenode来运行。
1.2、元数据目录说明
在第一次部署好hadoop集群的时候,我们需要在NameNode节点上格式化磁盘:hdfs namenode -format
格式化完成之后,将会在 $dfs.namenode.name.dir/current目录下产生如下的文件结构:
current/
|-- VERSION
|-- edits_*
|-- fsimage_0000000000008547077
|-- fsimage_0000000000008547077.md5
|-- seen_txid # 文件中记录的是edits滚动的序号,每次重启namenode时,namenode就知道要将哪些edits进行加载edits
dfs.name.dir 是 hdfs-site.xml 里配置的若干个目录组成的列表。
dfs.namenode.name.dir属性可以配置多个目录,如/data1/dfs/name, /data2/dfs/name, /data3/dfs/name …. 各个目录存储的文件结构和内容都完全一样,相当于备份,这样做的好处是当其中一个目录损坏了,也不会影响到hadoop的元数据,特别是当其中一个目录是NFS(网络文件系统 Network File System, NFS)之上,及时你这台机器损坏了,元数据也得到保存。
下面对 $dfs.namenode.name.dir/current/目录下的文件进行解释。
VERSION 文件
其是Java属性文件,内容大致如下:
#Fri Nov 15 19:47:46 CST 2013
namespaceID=934548976
clusterID=CID-cdff7d73-93cd-4783-9399-0a22e6dce196
cTime=0
storageType=NAME_NODE
blockpoolID=BP-893790215-192.168.24.72-1383809616115
layoutVersion=-47
其中:
1. namespaceID是文件系统的唯一标识符,在文件系统首次格式化之后生成的;
2. storageType说明这个文件存储的是什么进程的数据结构信息(如果是DataNode,storageType=DATA_NODE);
3. cTime表示NameNode存储时间的创建时间,由于我的NameNode没有更新过,所以这里的记录值为0,以后对NameNode升级之后,cTime将会记录更新时间戳;
4. layoutVersion表示HDFS永久性数据结构的版本信息,只要数据结构变更,版本号也要递减,此时HDFS也需要升级,否则磁盘仍旧是使用旧版本的数据结构,这会到孩子新版本的NameNode无法使用
5. clusterID是系统生成或手动指定的集群ID,在clusterID选项中可以使用它;如下说明:
a. 使用如下命令格式化一个NameNode:
$HADOOP_HOME/bin/hdfs namenode -format [-clusterId <cluster_id>]
选择一个唯一的cluster_id,并且这个cluster_id不能与环境中其他集群有冲突。如果没有提供cluster_id,则会自动生成一个唯一的ClusterID。
b、使用如下命令格式化其他Namenode:
$HADOOP_HOME/bin/hdfs namenode -format -clusterId <cluster_id>
c、升级集群至最新版本。在升级过程中需要提供一个ClusterID,例如:
$HADOOP_PREFIX_HOME/bin/hdfs start namenode --config $HADOOP_CONF_DIR -upgrade -clusterId <cluster_ID>
如果没有提供ClusterID,则会自动生成一个ClusterID。
blockpoolID:是针对每一个Namespace所对应的blockpool的ID,上面的这个BP-893790215-192.168.24.72-1383809616115就是在我的ns1的namespace下的存储块池的ID,
这个ID包括了其对应的NameNode节点的ip地址。
$dfs.namenode.name.dir/current/seen_txid
非常重要,是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾数,
namenode重启的时候,会按照seen_txid的数字,循序从头跑edits_0000001~到seen_txid的数字。所以当你的hdfs发生异常重启的时候,一定要比对seen_txid内的数字是不是你edits最后的尾数,
不然会发生建置namenode时metaData的资料有缺少,导致误删Datanode上多余Block的资讯。
$dfs.namenode.name.dir/current
目录下在format的同时也会生成fsimage和edits文件,及其对应的md5校验文件。
FsImage文件
FsImage文件中包含文件系统中所有目录和文件inode的序列化形式。每个inode是一个文件或目录的元数据的内部表示,并包含此类信息:文件的复制等级、修改和访问时间、访问权限、块大小以及组成文件的块。对于目录,则存储修改时间、权限和配额元数据FsImage文件没有记录块存储在哪个数据节点。而是由名称节点把这些映射保留在内存中,当数据节点加入HDFS集群时,数据节点会把自己所包含的块列表告知给名称节点,此后会定期执行这种告知操作,以确保名称节点的块映射是最新的。
1.3、NameNode启动
1)NameNode启动的时候,首先将FsImage文件中的内容加载到内存中,之后再执行EditLog文件中的各项操作,使得内存中的元数据和实际的同步,存在内存中的元数据支持客户端的读操作。
2)一旦在内存中成功建立文件系统元数据的映射,则创建一个新的FsImage文件和一个空的EditLog文件。
3)名称节点起来之后,HDFS中的更新操作会重新写到EditLog文件中,因为FsImage文件一般都很大(GB级别的很常见),如果所有的更新操作都往FsImage文件中添加,这样会导致系统运行的十分缓慢,但是,如果往EditLog文件里面写就不会这样,因为EditLog 要小很多。每次执行写操作之后,且在向客户端发送成功代码之前,edits文件都需要同步更新。
2、Secondary NameNode
Secondary NameNode 定期合并 fsimage 和 edits 日志,将 edits 日志文件大小控制在一个限度下。 Secondary NameNode处理流程
(1) 、 namenode 响应 Secondary namenode 请求,将 edit log 推送给 Secondary namenode , 开始重新写一个新的 edit log
(2) 、 Secondary namenode 收到来自 namenode 的 fsimage 文件和 edit log 。
(3) 、 Secondary namenode 将 fsimage 加载到内存,应用 edit log , 并生成一 个新的 fsimage 文件。
(4) 、 Secondary namenode 将新的 fsimage 推送给 Namenode 。
(5) 、 Namenode 用新的 fsimage 取代旧的 fsimage , 在 fstime 文件中记下检查 点发生的时间
3、数据存储细节
4、DataNode
DataNode的作用是HDFS中真正存储数据的。
如果一个文件非常大,比如100GB,那么怎么存储在DataNode中呢?DataNode在存储数据的时候是按照block为单位读写数据的。block是hdfs读写数据的基本单位。假设文件大小是100GB,从字节位置0开始,每64MB字节划分为一个block,依此类推,可以划分出很多的block。每个block默认是64MB大小。
Datanode 将 HDFS 数据以文件的形式存储在本地的文件系统中,它并不知道有 关 HDFS 文件的信息。它把每个 HDFS 数据块存储在本地文件系统的一个单独的文件 中。 Datanode 并不在同一个目录创建所有的文件,实际上,它用试探的方法来确定 每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所 有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目 录中支持大量的文件。 当一个 Datanode 启动时,它会扫描本地文件系统,产生一个这些本地文件对应 的所有 HDFS 数据块的列表,然后作为报告发送到 Namenode ,这个报告就是块状态报告。
5、Blocks块(最小化寻址,加快数据传输速度)
每个磁盘都有一个数据块大小(block size),这是一次可以读取或写入数据的最小单位。HDFS中也有数据块的概念,不过HDFS中的数据块却比一般磁盘的数据块(一般为512Byte)大得多。
像普通磁盘文件系统那样,HDFS把文件分割成block(下文如果没有特别声明,block都是指HDFS中的64MB大小的block)大小的数据块,并独立存储起来。不过与普通磁盘文件系统不同的是,
如果一个文件比单个block小,这个文件并不会用完整个block(如果一个几百kb的小文件占用了整个64MB大小的数据块,那该造成多大的浪费啊)。
HDFS为什么要使用大数据块?
HDFS中的数据块比普通磁盘文件系统要大得多,这么做的原因是最小化文件系统中数据寻址的时间。通过设置一个较大的block大小,寻址数据的时间就会比传输数据的时间小得多,从而处理一个大文件(HDFS主要用来处理大数据的嘛)的时间就主要决定于数据传输的时间了。如果数据寻址的时间平均为10ms,而传输速率为100MB/S,现在我们来大致计算一下,要想使数据寻址的时间只占到数据传输时间的1%,那么我们需要设置每个block大小为100MB。实际上默认的block大小为64MB(很多HDFS的其他实现也使用128MB)。以后block的大小还可能会随着数据传输速率的增加而增大。不过block的大小并不会一直增大下去。因为MapReduce中的Map任务每次只能处理一个block,对于同样大小的一个文件,如果block太大从而使map task太少的话,作业运行的时间反而会增加了
在分布式文件系统层面又抽象出一个block的概念可以带来有以下好处:
1. 由于没有一个文件必须存储在单个磁盘上的要求了,从而单个文件可以比集群中的任何一个节点的存储空间还要大,这样可以充分利用集群的存储能力。有可能(虽然不常见)一个文件会占用整个集群上所有节点的存储空间。
2. 以block(而不是文件)作为抽象单元简化了存储子系统。简单是所有存储系统的共同目标,在发生故障方式多种多样的分布式文件系统中尤为重要。存储子系统只需要处理block就可以了,从而简化了存储管理(因为block是固定大小的,可以很容易的计算出某个磁盘最多可以存储多少个block),而且还省去了元数据的管理负担(因为block只是需要存储的一串数据,文件的诸如访问权限之类的元数据不需要同block存储在一起,从而可以通过另一个系统namenode单独管理起来)。
3. 有了block,提供数据容错和可用性的冗余备份(replication)机制可以更好的工作。在HDFS中,为了防止数据块损坏,或者磁盘及机器当机,每一个block在不同机器上都有几份备份(默认为3)。如果一个block不能用了,HDFS会以一种对用户透明的方式拷贝一份新的备份出来,从而把集群的数据安全级别恢复到以前的水平(你也可以通过提高冗余备份数来提高数据的安全级别)。
可以使用HDFS中的fsck命令在block层面交互,例如运行命令:
hadoop fsck / -files -blocks 会列出文件系统根目录中组成所有文件的blocks。
6、HDFS文件读取的解析
文件读取流程
流程分析
•使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;
• Namenode会视情况返回文件的部分或者全部block列表,对于每个block,Namenode都会返回有该block拷贝的DataNode地址;
•客户端开发库Client会选取离客户端最接近的DataNode来读取block;如果客户端本身就是DataNode,那么将从本地直接获取数据.
•读取完当前block的数据后,关闭与当前的DataNode连接,并为读取下一个block寻找最佳的DataNode;
•当读完列表的block后,且文件读取还没有结束,客户端开发库会继续向Namenode获取下一批的block列表。
•读取完一个block都会进行checksum验证,如果读取datanode时出现错误,客户端会通知Namenode,然后再从下一个拥有该block拷贝的datanode继续读。
读操作就简单一些了,如图所示,client要从datanode上,读取FileA。而FileA由block1和block2组成。
那么,读操作流程为:
a. client向namenode发送读请求。
b. namenode查看Metadata信息,返回fileA的block的位置。
block1:host2,host1,host3
block2:host7,host8,host4
c. block的位置是有先后顺序的,先读block1,再读block2。而且block1去host2上读取;然后block2,去host7上读取;
上面例子中,client位于机架外,那么如果client位于机架内某个DataNode上,例如,client是host6。那么读取的时候,遵循的规律是:优选读取本机架上的数据。
7、HDFS文件写入的解析
文件写入流程
客户端要向HDFS写数据,首先要跟NameNode通信以确认可以写文件并获得接收文件block的DataNode,然后,客户端按顺序将文件逐个以block传递给相应DataNode,
并由接收到block的DataNode负责向其他DataNode复制block的副本。
流程分析
•使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;
•Namenode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会为文件 创建一个记录,否则会让客户端抛出异常;
•当客户端开始写入文件的时候,会将文件切分成多个packets,并在内部以数据队列"data queue"的形式管理这些packets,并向Namenode申请新的blocks,
获取用来存储replicas的合适的datanodes列表,列表的大小根据在Namenode中对replication的设置而定。
•开始以pipeline(管道)的形式将packet写入所有的replicas中。把packet以流的方式写入第一个datanode,该datanode把该packet存储之后,
再将其传递给在此pipeline中的下一个datanode,直到最后一个datanode,这种写数据的方式呈流水线的形式。
•最后一个datanode成功存储之后会返回一个ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",
成功收到datanode返回的ack packet后会从"ack queue"移除相应的packet。
•如果传输过程中,有某个datanode出现了故障,那么当前的pipeline会被关闭,出现故障的datanode会从当前的pipeline中移除,剩余的block会继续剩下的datanode中继续以pipeline的形式传输,
同时Namenode会分配一个新的datanode,保持replicas设定的数量。
有一个文件FileA,100M大小。Client将FileA写入到HDFS上。
HDFS按默认配置。
HDFS分布在三个机架上Rack1,Rack2,Rack3。
a. Client将FileA按64M分块。分成两块,block1和Block2;
b. Client向nameNode发送写数据请求,如图蓝色虚线①------>。
c. NameNode节点,记录block信息。并返回可用的DataNode,如粉色虚线②--------->。
Block1: host2,host1,host3
Block2: host7,host8,host4
原理:
NameNode具有RackAware机架感知功能,这个可以配置。
若client为DataNode节点,那存储block时,规则为:副本1,同client的节点上;副本2,不同机架节点上;副本3,同第二个副本机架的另一个节点上;其他副本随机挑选。
若client不为DataNode节点,那存储block时,规则为:副本1,随机选择一个节点上;副本2,不同副本1,机架上;副本3,同副本2相同的另一个节点上;其他副本随机挑选。
d. client向DataNode发送block1;发送过程是以流式写入。
流式写入过程,//逐个传输 host2-->host1--host3>
1>将64M的block1按64k的package划分;
2>然后将第一个package发送给host2;
3>host2接收完后,将第一个package发送给host1,同时client想host2发送第二个package;
4>host1接收完第一个package后,发送给host3,同时接收host2发来的第二个package。
5>以此类推,如图红线实线所示,直到将block1发送完毕。
6>host2,host1,host3向NameNode,host2向Client发送通知,说“消息发送完了”。如图粉红颜色实线所示。
7>client收到host2发来的消息后,向namenode发送消息,说我写完了。这样就真完成了。如图黄色粗实线
8>发送完block1后,再向host7,host8,host4发送block2,如图蓝色实线所示。
9>发送完block2后,host7,host8,host4向NameNode,host7向Client发送通知,如图浅绿色实线所示。
10>client向NameNode发送消息,说我写完了,如图黄色粗实线。。。这样就完毕了。
分析,通过写过程,我们可以了解到:
①写1T文件,我们需要3T的存储,3T的网络流量贷款。
②在执行读或写的过程中,NameNode和DataNode通过HeartBeat进行保存通信,确定DataNode活着。如果发现DataNode死掉了,就将死掉的DataNode上的数据,放到其他节点去。读取时,要读其他节点去。
③挂掉一个节点,没关系,还有其他节点可以备份;甚至,挂掉某一个机架,也没关系;其他机架上,也有备份。
那么问题来了,如果他们之间的一个datanode突然坏掉了怎么办?
1、如果传输过程中,有某个datanode出现了故障,那么当前的pipeline会被关闭,出现故障的datanode会从当前的pipeline中移除,剩余的block会继续剩下的datanode中继续以pipeline的形式传输,同时Namenode会分配一个新的datanode,保持replicas设定的数量。
2、关闭pipeline,将ack queue中的数据块放入data queue的开始。
3、当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。
4、失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。
5、元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。
6、客户端调用create()来创建文件
7、DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件。
8、元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
9、DistributedFileSystem返回DFSOutputStream,客户端用于写数据。
10、客户端开始写入数据,DFSOutputStream将数据分成块,写入data queue。
11、Data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。
12、Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
13、DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功
流水线复制
当客户端向 HDFS 文件写入数据的时候,一开始是写到本地临时文件中。假设该文件的副 本系数设置为 3 ,当本地临时文件累积到一个数据块的大小时,
客户端会从 Namenode 获取一个 Datanode 列表用于存放副本。然后客户端开始向第一个 Datanode 传输数据,第一个 Datanode 一小部分一小部分 (4 KB) 地接收数据,
将每一部分写入本地仓库,并同时传输该部分到列表中 第二个 Datanode 节点。第二个 Datanode 也是这样,一小部分一小部分地接收数据,写入本地 仓库,并同时传给第三个 Datanode 。
最后,第三个 Datanode 接收数据并存储在本地。因此, Datanode 能流水线式地从前一个节点接收数据,并在同时转发给下一个节点,数据以流水线的 方式从前一个 Datanode 复制到下一个
更细节的原理
客户端创建文件的请求其实并没有立即发送给 Namenode ,事实上,在刚开始阶 段 HDFS 客户端会先将文件数据缓存到本地的一个临时文件。应用程序的写操作被透 明地重定向到这个临时文件。
当这个临时文件累积的数据量超过一个数据块的大小 ,客户端才会联系 Namenode 。 Namenode 将文件名插入文件系统的层次结构中,并 且分配一个数据块给它。
然后返回 Datanode 的标识符和目标数据块给客户端。接着 客户端将这块数据从本地临时文件上传到指定的 Datanode 上。
当文件关闭时,在临 时文件中剩余的没有上传的数据也会传输到指定的 Datanode 上。然后客户端告诉 Namenode 文件已经关闭。此时 Namenode 才将文件创建操作提交到日志里进行存储 。
如果 Namenode 在文件关闭前宕机了,则该文件将丢失。
8、HDFS通信协议
所有的 HDFS 通讯协议都是构建在 TCP/IP 协议上。客户端通过一个可配置的端口连接到 Namenode , 通过 ClientProtocol 与 Namenode 交互。而 Datanode 是使用 DatanodeProtocol 与 Namenode 交互。在设计上, DataNode 通过周期性的向 NameNode 发送心跳和数据块来保持和 NameNode 的通信,数据块报告的信息包括数据块的属性,即数据块属于哪 个文件,数据块 ID ,修改时间等, NameNode 的 DataNode 和数据块的映射 关系就是通过系统启动时 DataNode 的数据块报告建立的。从 ClientProtocol 和 Datanodeprotocol 抽象出一个远程调用 ( RPC ), 在设计上, Namenode 不会主动发起 RPC , 而是是响应来自客户端和 Datanode 的 RPC 请求。
9、HDFS的安全模式
Namenode 启动后会进入一个称为安全模式的特殊状态。处于安全模式 的 Namenode 是不会进行数据块的复制的。 Namenode 从所有的 Datanode 接收心跳信号和块状态报告。块状态报告包括了某个 Datanode 所有的数据 块列表。每个数据块都有一个指定的最小副本数。当 Namenode 检测确认某 个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全 (safely replicated) 的;在一定百分比(这个参数可配置)的数据块被 Namenode 检测确认是安全之后(加上一个额外的 30 秒等待时间),Namenode 将退出安全模式状态。接下来它会确定还有哪些数据块的副本没 有达到指定数目,并将这些数据块复制到其他 Datanode 上。
10、副本机制
特点
1. 数据类型单一
2. 副本数比较多
3. 写文件时副本的放置方法
4. 动态的副本创建策略
5. 弱化的副本一致性要求
副本摆放策略
修改副本数
集群只有三个Datanode,hadoop系统replication=4时,会出现什么情况?
对于上传文件到hdfs上时,当时hadoop的副本系数是几,这个文件的块数副本数就会有几份,无论以后你怎么更改系统副本系统,这个文件的副本数都不会改变,也就说上传到分布式系统上的文件副本数由当时的系统副本数决定,不会受replication的更改而变化,除非用命令来更改文件的副本数。因为dfs.replication实质上是client参数,在create文件时可以指定具体replication,属性dfs.replication是不指定具体replication时的采用默认备份数。文件上传后,备份数已定,修改dfs.replication是不会影响以前的文件的,也不会影响后面指定备份数的文件。只影响后面采用默认备份数的文件。但可以利用hadoop提供的命令后期改某文件的备份数:hadoop fs -setrep -R 1。如果你是在hdfs-site.xml设置了dfs.replication,这并一定就得了,因为你可能没把conf文件夹加入到你的 project的classpath里,你的程序运行时取的dfs.replication可能是hdfs-default.xml里的 dfs.replication,默认是3。可能这个就是造成你为什么dfs.replication老是3的原因。你可以试试在创建文件时,显式设定replication。replication一般到3就可以了,大了意义也不大。
副本
副本就是备份,目的当时是为了安全。正是因为集群环境的不可靠,所以才使用副本机制来保证数据的安全性。
副本的缺点就是会占用大量的存储空间。副本越多,占用的空间越多。相比数据丢失的风险,存储空间的花费还是值得的。
那么,一个文件有几个副本合适呢?我们查看hdfs-default.xml文件。
默认的副本数量是3。意味着HDFS中的每个数据块都有3份。当然,每一份肯定会尽力分配在不同的DataNode服务器中。
试想:如果备份的3份数据都在同一台服务器上,那么这台服务器停机了,是不是所有的数据都丢了啊?
11、HDFS负载均衡
HDFS的数据也许并不是非常均匀的分布在各个DataNode中。一个常见的原因是在现有的集群上经常会增添新的DataNode节点。当新增一个数据块(一个文件的数据被保存在一系列的块中)时,
NameNode在选择DataNode接收这个数据块之前,会考虑到很多因素。其中的一些考虑的是:
•将数据块的一个副本放在正在写这个数据块的节点上。
•尽量将数据块的不同副本分布在不同的机架上,这样集群可在完全失去某一机架的情况下还能存活。
•一个副本通常被放置在和写文件的节点同一机架的某个节点上,这样可以减少跨越机架的网络I/O。
•尽量均匀地将HDFS数据分布在集群的DataNode中。
12、HDFS机架感知
通常,大型 Hadoop 集群是以机架的形式来组织的,同一个机架上不同 节点间的网络状况比不同机架之间的更为理想。 另外, NameNode 设法将 数据块副本保存在不同的机架上以提高容错性。
而 HDFS 不能够自动判断集群中各个 datanode 的网络拓扑情况 Hadoop 允 许集群的管理员通过配置 dfs.network.script 参数来确定节点所处的机架。
文 件提供了 IP->rackid 的翻译。 NameNode 通过这个得到集群中各个 datanode 机器的 rackid 。 如果 topology.script.file.name 没有设定,则每个 IP 都会翻译 成 / default-rack 。
有了机架感知, NameNode 就可以画出上图所示的 datanode 网络拓扑图。 D1,R1 都是交换机,最底层是 datanode 。 则 H1 的 rackid=/D1/R1/H1 , H1 的 parent 是 R1 , R1 的是 D1 。
这些 rackid 信息可以通过 topology.script.file.name 配置。有了这些 rackid 信息就可以计算出任意两台 datanode 之间的距离。
distance(/D1/R1/H1,/D1/R1/H1)=0 相同的 datanode
distance(/D1/R1/H1,/D1/R1/H2)=2 同一 rack 下的不同 datanode
distance(/D1/R1/H1,/D1/R1/H4)=4 同一 IDC 下的不同 datanode
distance(/D1/R1/H1,/D2/R3/H7)=6 不同 IDC 下的 datanode
13、HDFS访问方式
HDFS 给应用提供了多种访问方式。用户可以通过 Java API 接口访问,也 可以通过 C 语言的封装 API 访问,还可以通过浏览器的方式访问 HDFS 中的文件。
14、HDFS 健壮性;数据出错与恢复
HDFS 的主要目标就是即使在出错的情况下也要保证数据存储的可靠性。 常见的三种出错情况是: Namenode 出错 , Datanode 出错和网络割裂 ( network partitions) 。
1>名称节点出错
名称节点保存着最核心的连个文件FsImage和EditLog,当这两个文件损坏,那么整个文件系统都将失效。因此,HDFS设置了备份机制,通过SecondaryNameNode上的FsImage和EditLog来进行数据恢复。FsImage 和 Editlog 是 HDFS 的核心数据结构。如果这些文件损坏了,整个 HDFS 实例都将失效。因而, Namenode 可以配置成支持维护多个 FsImage 和 Editlog 的副本。任何对 FsImage 或者 Editlog 的修改,都将同步到它们的副 本上。这种多副本的同步操作可能会降低 Namenode 每秒处理的名字空间事 务数量。然而这个代价是可以接受的,因为即使 HDFS 的应用是数据密集的 ,它们也非元数据密集的。当 Namenode 重启的时候,它会选取最近的完整 的 FsImage 和 Editlog 来使用。Namenode 是 HDFS 集群中的单点故障 (single point of failure) 所在。如果 Namenode 机器故障,是需要手工干预的。目前,自动重启或在另一台机器 上做 Namenode 故障转移的功能还没实现。
2>数据节点出错 磁盘数据错误,心跳检测和重新复制
每个数据节点会定期的想名称节点发送心跳,当网络或者数据节点出现故障时,名称节点就无法接收到心跳信息。那么将把没有心跳信息的节点标记为“宕机”,对应节点上的所有信息都会标记为“不可读”,这样就导致一些数据块副本数量小于冗余因子。名称节点会定期的检查每个副本的冗余情况,一旦发现某个文件的副本数量小于冗余因子,就会启动数据冗余复制生成新的副本。
每个 Datanode 节点周期性地向 Namenode 发送心跳信号。网络割裂可能 导致一部分 Datanode 跟 Namenode 失去联系。Namenode 通过心跳信号的缺 失来检测这一情况,并将这些近期不再发送心跳信号 Datanode 标记为宕机 ,不会再将新的 IO 请求发给它们。任何存储在宕机 Datanode 上的数据将不 再有效。 Datanode 的宕机可能会引起一些数据块的副本系数低于指定值, Namenode 不断地检测这些需要复制的数据块,一旦发现就启动复制操作。在下列情况下,可能需要重新复制:某个 Datanode 节点失效,某个副本遭 到损坏, Datanode 上的硬盘错误,或者文件的副本系数增大。
3>数据出错 数据完整性
文件被创建的时候,客户端就会对每一个文件进行信息摘录,并把这些信息写入同一路径下的隐藏文件夹下面。当客户端读取到数据后,会对每一个文件快进行MD5和sha1校验。
如果校验出错,就会请求读取其他节点的同一数据块,并向名称节点报告这个文件有错误,名称节点会定期的检查并且重新复制这个块。
从某个 Datanode 获取的数据块有可能是损坏的,损坏可能是由 Datanode 的存储设备错误、网络错误或者软件 bug 造成的。 HDFS 客户端软 件实现了对 HDFS 文件内容的校验和 (checksum) 检查。
当客户端创建一个新 的 HDFS 文件,会计算这个文件每个数据块的校验和,并将校验和作为一个 单独的隐藏文件保存在同一个 HDFS 名字空间下。当客户端获取文件内容后 ,
它会检验从 Datanode 获取的数据跟相应的校验和文件中的校验和是否匹 配,如果不匹配,客户端可以选择从其他 Datanode 获取该数据块的副本。
15、快照
快照支持某一特定时刻的数据的复制备份。利用快照,可以让 HDFS 在 数据损坏时恢复到过去一个已知正确的时间点。 HDFS 目前还不支持快照功 能,但计划在将来的版本进行支持。
16、HDFS 文件删除恢复机制
当用户或应用程序删除某个文件时,这个文件并没有立刻从 HDFS 中删 除。实际上, HDFS 会将这个文件重命名转移到 /trash 目录。只要文件还在 /trash 目录中,该文件就可以被迅速地恢复。
文件在 /trash 中保存的时间是可 配置的,当超过这个时间时, Namenode 就会将该文件从名字空间中删除。 删除文件会使得该文件相关的数据块被释放。注意,
从用户删除文件到 HDFS 空闲空间的增加之间会有一定时间的延迟。
只要被删除的文件还在 /trash 目录中,用户就可以恢复这个文件。如果 用户想恢复被删除的文件,可以浏览 /trash 目录找回该文件。 /trash 目 录仅仅保存被删除文件的最后副本。
/trash 目录与其他的目录没有什么区别 ,除了一点:在该目录上 HDFS 会应用一个特殊策略来自动删除文件。目前 的默认策略是删除 /trash 中保留时间超过 6 小时的文件。
将来,这个策略可以 通过一个被良好定义的接口配置。
开启回收站
hdfs-site.xml
<configuration>
<property>
<name>fs.trash.interval</name>
<value> 1440 </value>
<description>Number ofminutes between trash checkpoints.
If zero, the trashfeature is disabled.
</description>
</property>
</configuration>
1, fs.trash.interval参数设置保留时间为 1440 分钟(1天)
2, 回收站的位置:在HDFS上的 /user/$USER/.Trash/Current/
17、HDFS 分布式缓存(DistributedCache )
(1)在HDFS上准备好要共享的数据(text、archive、jar),你拼路径的时候必须加前缀"file://"说明是本地路径,否则hadoop默认访问的路径是hdfs。
(2)DistributedCache 在 Mapper 或者 Reducer 启动时会被 copy to local,然后被 DistributedCache.getLocalCacheFiles() 调用,运行完 job 后 local cache file 会被删掉,
如果另一个 job 也需要这样一份文件,需要重新添加、重新缓存,因为在分布式场景下 task 并不知道该 node 是否存在 cache file。如果在同台机器已经有了dist cache file,
不会再次download,DistributedCache 根据缓存文档修改的时间戳进行追踪。 在作业执行期间,当前应用程序或者外部程序不能修改缓存文件,所以分布式缓存一般用来缓存只读文件。
(3)DistributedCache 在添加的时候注意要添加具体的文件,如果你添加目录,DistributedCache 将不会自动遍历、识别目录下的文件。
18、HDFS Fedoration机制
namenode在内存中保存着文件系统中每个文件和目录的引用,但集群规模扩大时,这便造成了一个瓶颈。于是在hadoop 2.x发行版中引入了一个新的概念:Hadoop Fedoration。
它允许集群拥有不止一个namenode,这样每个namenode只负责维护文件系统中的一部分,例如一个namenode维护/user目录,另一个namenode可以维护/share目录。
在fedoration中,每个namenode维护两部分信息:
1)由namespace 元数据组成的namespace volume;
2)包含其负责维护的某一部分文件系统中的的所有文件的block位置信息的block pool。
namespace volume各自之间是独立的,这就意味着namenode之间不用交互,
而且某个namenode宕机并不影响其他namenode的正常使用。相对于namespace volume而言,Block pool并不是分区的,所以datanodes需要向集群中的每个namenode注册,并
且可能要存储来自多个block pool的数据。
要想使用带有fedoration特性的cluster,用户可以使用用户端的挂载表来映射文件路径到namenode。这个可以通过ViewFileSystem来配置,并使用viewfs:// URI.
19、HDFS High-Availabilty
虽然通过在多个文件系统备份namespace metadata和使用secondary namenode来定期合并namespace image和edit log以产生新的checkpoint可以保护集群以免数据丢失。
但这并没有提供集群的高可用性,因为namenode本身仍然是一个单点故障——如果namenode当掉了,所有的客户端,包括mapreduce作业都无法正常读、写以及查看文件了,
因为namenode是维护namespace metadata和提供file-to-block映射的唯一库。
要想从失败的namenode中恢复,管理员应启动一个新的namenode,同时配置datanode和用户使用这个新的namenode。这个新的namenode暂时还不能正常运作,直到它做完了以下几件事:
1) 把namespace image备份加载入内存;
2) 重放edit log中的操作;
3) 从datanode中接受足够的block report(也就是记录各个datanode中block的信息以确定file-to-block映射),然后离开safe mode。
在有很多节点和文件的大的集群中,这个操作可能要花费几十分钟的时间!!
Hadoop 2.x发行版通过加入对HDFS High-Availabilty的支持而有效避免了长时间的downtime。在这种实现中,有一对namenode,它们分别配置为active和standby。
当active namenode当掉时,standby namenode立即接手继续为client提供服务,期间的中断时间很小。为了实现HDFS High-Availabilty,结构上发生了以下变化:
1) 两个namenode使用一个高可用的共享设备(最初HA实现使用的是NFS来共享edit log,不过在未来的版本中会提供更多的选项,
如构建于ZooKeeper之上的基于BookKeeper的系统)来存储edit log,当standby namenode接手运行时,它就会立即重放edit log中的操作(同时它也充当着secondary namenode的角色,
不停地合并老的namespace image和新的edit log以免edit log过大),从而很快达到与active namenode当掉前的状态。
2) datanode需要向两个namenode发送block report,因为block mapping是存放在内存,而不是磁盘中的。
3) 用户端(client)必须被合适配置并采用一种对用户透明的方式处理namenode的失败恢复。综合起来,如下图所示:
有了以上改变做基础,当active namenode当掉时,因为standy namenode保存着最新的edit log(同时还有上个检查点镜像文件)和最新的block mapping,
standy namenode可以在几十秒内很快地接手继续工作。在实际应用中测得的失败恢复时间会长一些(大约一分钟左右),因为系统需要额外的时间确定active namenode确实已经当机了。
HA与Federation
20、 常见问题分析
1)、HDFS可不可以用来做网盘
答案:不可以,网盘只存储,不用做分析,hdfs在增加节点,同时也加大了分析能力,主要是大容量存储之上的数据分析
1、容量成本太高,
2、文件大小不确定,如果存大量小文件会造成很大的浪费
3、相对于网盘来说,文件读写的效率低
4、只适合一次写入,多次读取的操作
5、hdfs不支持文件内容修改,可支持往文件尾部追加内容。
2)、 HDFS大量小文件存储
1、对于待上传的文件,先将小文件合并为一个大文件再上传,利用SequenceFile、MapFile、Har等方式归档小文件,这个方法的原理就是把小文件归档起来管理,
HBase就是基于此的。对于这种方法,如果想找回原来的小文件内容,那就必须得知道与归档文件的映射关系。
2、如果对于已经上传了的文件,需要进行合并的话,我们可以使用Map-redure来进行归档。
3、BlueSky解决方案,以一种two-level prefetching机制以提高小文件读取效率,即索引文件预取和数据文件预取。索引文件预取是指当用户访问某个文件时,
该文件所在的block对应的索引文件被加载到内存中,这样,用户访问这些文件时不必再与namenode交互了。数据文件预取是指用户访问某个文件时,将该文件所在课件中的所有文件加载到内存中,
这样,如果用户继续访问其他文件,速度会明显提高。
二、MapReduce
1、MapReduce原理
Hadoop MapReduce是一个快速、高效、简单用于编写并行处理大数据程序并应用在大集群上的编程框架。其前身是Google公司的MapReduce。
MapReduce是Google公司的核心计算模型,它将复杂的、运行于大规模集群上的并行计算过程高度地抽象到了两个函数:Map和Reduce。
适合用MapReduce来处理的数据集(或任务),需要满足一个基本要求:待处理的数据集可以分解成许多小的数据集,而且每一个小数据集都可以完全并行地进行处理。
概念“Map”(映射)和“Reduce”(归约),以及它们的主要思想,都是从函数式编程语言里借来的,同时包含了从矢量编程语言里借来的特性。
Hadoop MapReduce极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。
一个MapReduce作业(job)通常会把输入的数据集切分为若干独立的数据块,由map任务(task)以完全并行的方式处理它们。框架会对map的输出先进行排序,然后把结果输入给reduce任务。
通常,作业的输入和输出都会被存储在文件系统中。整个框架负责任务的调度和监控,以及重新执行已经失败的任务。
通常,MapReduce框架的计算节点和存储节点是运行在一组相同的节点上的,也就是说,运行MapReduce框架和运行HDFS文件系统的节点通常是在一起的。
这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这可以使整个集群的网络带宽被非常高效地利用。
MapReduce框架包括一个主节点(ResourceManager)、多个子节点(运行NodeManager)和MRAppMaster(每个任务一个)共同组成。
应用程序至少应该指明输入/输出的位置(路径),并通过实现合适的接口或抽象类提供map和reduce函数,再加上其他作业的参数,就构成了作业配置(job configuration)。
Hadoop的job client提交作业(jar包/可执行程序等)和配置信息给ResourceManager,后者负责分发这些软件和配置信息给slave、调度任务且监控它们的执行,同时提供状态和诊断信息给job-client。
虽然Hadoop框架是用Java实现的,但MapReduce应用程序则不一定要用Java来写,也可以使用Ruby、Python、C++等来编写。
MapReduce框架的流程如图2-6所示。
针对上面的流程可以分为两个阶段来描述。
1.1、Map阶段
1)InputFormat根据输入文件产生键值对,并传送到Mapper类的map函数中;
2)map输出键值对到一个没有排序的缓冲内存中;
3)当缓冲内存达到给定值或者map任务完成,在缓冲内存中的键值对就会被排序,然后输出到磁盘中的溢出文件;
4)如果有多个溢出文件,那么就会整合这些文件到一个文件中,且是排序的;
5)这些排序过的、在溢出文件中的键值对会等待Reducer的获取。
1.2、Reduce阶段
1)Reducer获取Mapper的记录,然后产生另外的键值对,最后输出到HDFS中;
2)shuffle:相同的key被传送到同一个的Reducer中;
3)当有一个Mapper完成后,Reducer就开始获取相关数据,所有的溢出文件会被排序到一个内存缓冲区中;
4)当内存缓冲区满了后,就会产生溢出文件到本地磁盘;
5)当Reducer所有相关的数据都传输完成后,所有溢出文件就会被整合和排序;
6)Reducer中的reduce方法针对每个key调用一次;
7)Reducer的输出到HDFS。
三、yarn
Hadoop YARN原理
经典MapReduce的最严重的限制主要关系到可伸缩性、资源利用和对与MapReduce不同的工作负载的支持。在MapReduce框架中,作业执行受两种类型的进程控制:
一个称为JobTracker的主要进程,它协调在集群上运行的所有作业,分配要在TaskTracker上运行的map和reduce任务。
另一个就是许多称为TaskTracker的下级进程,它们运行分配的任务并定期向JobTracker报告进度。
这时,经过工程师们的努力,诞生了一种全新的Hadoop架构——YARN(也称为MRv2)。
YARN称为下一代Hadoop计算平台,主要包括ResourceManager、ApplicationMaster、NodeManager,其中ResourceManager用来代替集群管理器,ApplicationMaster代替一个专用且短暂的JobTracker,
NodeManager代替TaskTracker。
MRv2最核心的思想就是将JobTracker两个主要的功能分离成单独的组件,这两个功能是资源管理和任务调度/监控。新的资源管理器全局管理所有应用程序计算资源的分配,
每一个应用的ApplicationMaster负责相应的调度和协调。
一个应用程序要么是一个单独的传统的MapReduce任务或者是一个DAG(有向无环图)任务。
ResourceManager和每一台机器的节点管理服务(NodeManger)能够管理用户在那台机器上的进程并能对计算进行组织。
事实上,每一个应用的ApplicationMaster是一个特定的框架库,它和ResourceManager来协调资源,和NodeManager协同工作以运行和监控任务。
ResourceManager有两个重要的组件:Scheduler和ApplicationsManager。
Scheduler负责分配资源给每个正在运行的应用,同时需要注意Scheduler是一个单一的分配资源的组件,不负责监控或者跟踪任务状态的任务,而且它不保证重启失败的任务。
ApplicationsManager注意负责接受任务的提交和执行应用的第一个容器ApplicationMaster协调,同时提供当任务失败时重启的服务。
如图2-7所示,客户端提交任务到ResourceManager的ApplicationsManager,然后Scheduler在获得了集群各个节点的资源后,
为每个应用启动一个App Mastr(ApplicationMaster),用于执行任务。每个App Mastr启动一个或多个Container用于实际执行任务。
参考:
《Hadoop大数据分析与挖掘实战》——2.3节Hadoop原理
https://cloud.tencent.com/developer/article/1043733
https://www.cnblogs.com/growth-hong/p/6396332.html
https://blog.csdn.net/yinglish_/article/details/75269649
https://blog.csdn.net/u011987514/article/details/76255019
https://blog.csdn.net/xjz729827161/article/details/79463140
https://blog.csdn.net/wypersist/article/details/79757242
https://blog.csdn.net/qq_40784783/article/details/79104327
https://www.cnblogs.com/codeOfLife/p/5375120.html
https://www.cnblogs.com/caiyisen/p/7395843.html
http://bigdata.it168.com/a2018/0525/3205/000003205248.shtml
http://dataunion.org/8798.html
https://yq.aliyun.com/articles/108760
https://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-name-node/index.html
http://hexiaoqiao.github.io/blog/2018/03/30/the-analysis-of-basic-principle-of-hdfs-ha-using-qjm/
https://read01.com/dENyKN.html#.W4U3qvkzapp
https://www.jianshu.com/p/968a30a6b8c8
https://www.cnblogs.com/duanxz/p/3874009.html
https://blog.csdn.net/liudongdong0909/article/details/79168146
https://blog.csdn.net/shui2104/article/details/52624444
https://www.cnblogs.com/gisorange/p/4328859.html
https://blog.csdn.net/sdksdk0/article/details/51622547
http://blog.51cto.com/hmtk520/1943976
http://www.cnblogs.com/mindwind/p/4833098.html
https://www.jianshu.com/p/7d1bdd23c460
http://flyingdutchman.iteye.com/blog/1900536
http://www.cnblogs.com/beanmoon/archive/2012/12/11/2809315.html
http://shiyanjun.cn/archives/942.html
http://dj1211.com/?p=178
https://www.linuxidc.com/Linux/2012-06/62885.htm
————————————————
版权声明:本文为CSDN博主「哎呦、不错哦」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/l1394049664/article/details/82191835