目录
1 简介
Hadoop 是Apache基金会下一个开源的分布式计算平台,它以分布式文件系统HDFS和MapReduce算法为核心,为用户提供了系统底层细节透明的分布式基础架构。用户可以在不了解分布式底层细节的情况下,充分利用分布式集群进行高速运算和存储。
Hadoop是一个能够让用户轻松架构和使用的分布式计算平台。它主要有以下几个优点:
①高可靠性。Hadoop按位存储和处理数据的能力值得人们信赖。
②高扩展性。Hadoop是在可用的计算机集簇间分配数据并完成计算任务的,这些集簇可以方便地扩展到数以千计的节点中。
③高效性。Hadoop能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此处理速度非常快。
④高容错性。Hadoop能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配。
⑤低成本。与一体机、商用数据仓库以及QlikView、Yonghong Z-Suite等数据集市相比,Hadoop是开源的,项目的软件成本因此会大大降低。
缺点:
①不适合低延迟数据访问。
②无法高效存储大量小文件,会占用大量的namenode内存。
③不支持多用户写入以及任意修改文件。
Hadoop无非就是:HDFS(文件系统),yarn(任务调配),mapReduce(编程模型,大数据并行运算),我们安装完hadoop就已经包括了以上;
2 HDFS
Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。HDFS放宽了一部分POSIX约束,来实现流式读取文件系统数据的目的。HDFS在最开始是作为Apache Nutch搜索引擎项目的基础架构而开发的。HDFS是Apache Hadoop Core项目的一部分。
Hdfs主要模块:NameNode、DataNode
以下是对HDFS的设计简单描述(详细可以参阅该文章):
- 超大文件 :“超大文件”在这里指具有几百MB、几百GB甚至几百TB大小的文件。目前已经有存储PB级数据的Hadoop集群了。
- 流式数据访问 :HDFS的构建思路是这样的:一次写入、多次读取是最高效的访问模式。数据集通常由数据源生成或从数据源复制而来,接着长时间 在此数据集上进行各种分析。每次分析都将涉及该数据集的大部分数据甚至全部,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
- 商用硬件 :Hadoop并不需要运行在昂贵且高可靠的硬件上。
- 低时间延迟的数据访问 :要求低时间延迟数据访问的应用,例如几十毫秒范围,不适合在HDFS上运行。HDFS是为高数据吞吐量应用优化的,这可能会以提高时间延迟为代价。对于低延迟的访问需求,HBase是更好的选择。
- 大量的小文件 :由于namenode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总数受限于NameNode的内存容量。
- 多用户写入,任意修改文件 :HDFS中的文件写入只支持单个写入者,而且写操作总是以“只添加”方式在文件末尾写数据。它不支持多个写入者的操作,也不支持在文件的任意位置进行修改。但可能以后会支持,不过这种相对比较低效。
2.1 架构原理
HDFS采用master/slave架构。一个HDFS集群包含一个单独的NameNode和多个DataNode。
NameNode作为master服务,它负责管理文件系统的命名空间和客户端对文件的访问。NameNode会保存文件系统的具体信息,包括文件信息、文件被分割成具体block块的信息、以及每一个block块归属的DataNode的信息。对于整个集群来说,HDFS通过NameNode对用户提供了一个单一的命名空间。
DataNode作为slave服务,在集群中可以存在多个。通常每一个DataNode都对应于一个物理节点。DataNode负责管理节点上它们拥有的存储,它将存储划分为多个block块,管理block块信息,同时周期性的将其所有的block块信息发送给NameNode。
下图为HDFS系统架构图,主要有三个角色,Client、NameNode、DataNode。
hdfs结构
Namenode:namenode是一个名称节点,是hdfs的大脑,它维护着文件系统的目录树。
Secondarynode:第二个名字节点,用于备份,一旦namenode挂掉,那么secondarynode就补上。
datanode:data节点用来存储数据。
Client:客户机是用来读写数据。
2.2 HDFS的概念
namenode
负责管理工作(管理文件系统的目录结构,元数据信息,响应用户请求)
包含了两个核心的数据结构,FsImage和EditLog。
FsImage:用于维护整个文件系统数以及文件树中所有的文件和文件夹的元数据
EditLog:记录了所有针对文件的创建,删除,重命名等操作
NameNode目录结构
运行中的NameNode有如下所示的目录结构:
- VERSION文件 :是一个Java属性文件,其中包含正在运行的HDFS的版本信息。该文件一般包含以下内容:
#Mon Sep 29 09:54:36 BST 2014
namespaceID=1342387246
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
cTime=0
storageType=NAME_NODE
blockpoolID=BP-526805057-127.0.0.1-1411980876842
layoutVersion=-57
-
- layoutVersion :这是一个负整数,描述HDFS持久性数据结构(也称布局)的版本,但是该版本号与Hadoop发布包的版本号无关。只要布局变更,版本号将会递减,此时HDFS也要升级。否则,新版本的NameNode(或DataNode)就无法正常工作。
- namespaceID :文件系统命名空间的唯一标识符,是在NameNode首次格式化时创建的。
- clusterID : 在HDFS集群上作为一个整体赋予的唯一标识符,这对于联邦HDFS非常重要。
- blockpoolID :数据块池的唯一标识符,数据块池中包含了由一个NameNode管理的命名空间中的所有文件。
- cTime :标记了NameNode存储系统的创建时间。刚格式化的存储系统,值为0,但升级后,该值会更新到新的时间戳。
- storageType :该存储目录包含的时NameNode的数据结构。
编辑日志(edits log)与命名空间镜像文件(fsimage):
编辑日志(edits log) :文件系统客户端执行写操作时,这些事务首先被记录到edits中。NameNode在内存中维护文件系统的元数据;当被修改时,相关元数据信息也同步更新。内存中的元数据可支持客户端的读请求。
命名空间镜像文件(fsimage):文件系统元数据的持久检查点,每个fsimage文件包含文件系统中的所有目录和文件inode的序列化信息(从Hadoop-2.4.0起,FSImage开始采用Google Protobuf编码格式),每个inodes表征一个文件或目录的元数据信息以及文件的副本数、修改和访问时间等信息。数据块存储在DataNode中,但fsimage文件并不描述DataNode。
-
seen_txid文件 :该文件对于NameNode非常重要,它是存放transactionId的文件,format之后是0,它代表的是NameNode里面的edits_*文件的尾数,NameNode重启的时候,会按照seen_txid的数字,循序从头跑edits_000*01~到seen_txid的数字。当hdfs发生异常重启的时候,一定要比对seen_txid内的数字是不是你edits最后的尾数,不然会发生建置NameNode时元数据信息缺失,导致误删DataNode上多余block。
-
in_use.lock文件 :是一个锁文件,NameNode使用该文件为存储目录加锁。可以避免其他NameNode实例同时使用(可能会破坏)同一个存储目录的情况。
NameNode的工作原理
NameNode管理文件系统的命名空间。它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件(fsimage)和编辑日志文件(edits log)。它也记录着每个文件中各个块所在的数据节点信息,但它并不永久保存块的位置信息,因为这些信息会在系统启动时根据DataNode节点信息重建,块信息存储在内存中。
可以看得出来NameNode的正常运行是非常重要的,如果运行的NameNode服务的机器毁坏,文件系统上所有的文件将会丢失,因为我们不知道如何根据DataNode的块重建文件。因此,Hadoop为此提供两种实现NameNode容错机制:
- 备份组成文件系统元数据持久状态的文件。一般是将持久状态写入本地磁盘的同时,写入一个远程挂载的网络文件系统(NFS),HDFS与NFS安装配置可以参考该文章
- 运行一个辅助NameNode。但它不能作为主NameNode,这个辅助NameNode的重要作用是定期合并编辑日志(edits)与命名空间镜像文件(fsimage),以防止编辑日志过大。一般来说辅助NameNode在一个单独的机器上运行,因为它需要占用大量CPU时间并且一样多的内存来执行合并操作。设计成这样的好处在于,一旦主NameNode发生故障,辅助NameNode立刻就可以接替它的工作,但是由于保存数据是定时进行的,所以难免会有损失的数据,此时就可以把保存在其他地方(NFS)的数据复制到辅助NameNode,然后辅助NameNode作为新的主NameNode运行(注意,也可以运行热备份NameNode代替运行辅助NameNode)。
Seconday NameNode(辅助NameNode)
为主namenode内存中的文件系统元数据,创建检查点,在文件系统中设置一个检查点来帮助NameNode更好的工作,不是取代掉NameNode,也不是备份SecondayName有两个作用
一是镜像备份,二是日志与镜像的定期合并。两个同时进行称为checkpoint。
镜像备份的作用:备份fsImage
合并作用:防止如果NameNode节点故障,namenode下次启动时,会把fsImage加载到内存中,应用editLog,EditLog往往很大,可以减少重启时间,同时保证HDFS系统的完整性。
运行中的SecondaryNamenode(辅助NameNode)的目录结构与主NameNode的目录结构几乎一样,但有部分时间不相同,它为主NameNode内存中的文件系统元数据创建检查点(后面解释)尚未成功时两者不相同。运行中的SecondaryNamenode有如下所示的目录结构:
当NameNode 启动时,需要合并fsimage和edits文件,按照edits文件内容将fsimage进行事务处理,从而得到HDFS的最新状态。实际应用中,NameNode很少重新启动。假如存在一个庞大的集群,且关于HDFS的操作相当频繁与复杂,那么就会产生一个非常大的edits文件用于记录操作,这就带来了以下问题:
- edits文件过大会带来管理问题;
- 一旦需要重启HDFS时,就需要花费很长一段时间对edits和fsimage进行合并,这就导致HDFS长时间内无法启动;
- 如果NameNode挂掉了,会丢失部分操作记录(这部分记录存储在内存中,还未写入edits);
此时,Secondary NameNode就要发挥它的作用了:合并edits文件,防止edits文件持续增长。该辅助NameNode会为主NameNode内存中的文件系统元数据创建检查点(fsimage文件),创建检查点前HDFS会自动进入安全模式(safe mode),当NameNode处在安全模式,管理员也可手动调用hdfs dfsadmin -saveNameSpace命令来创建检查点。创建检查点的步骤如下所示(如图中也简单地描述)。
- 辅助NameNode请求主NameNode停止使用正在进行中的edits文件,这样新的编辑操作记录到一个新文件中。主NameNode还会更新所有存储目录中的seen_txid文件。
- 辅助NameNode从主NameNode获取最近的fsimage和edits文件(采用HTTP GET)。
- 辅助NameNode将fsimage文件载入内存,逐一执行edits文件中的事务,创建新的合并后的fsimage文件。
- 辅助NameNode将新的fsimage文件发送回主NameNode(使用HTTP PUT),主NameNode将其保存为临时的.ckpt文件。
- 主NameNode重新命名临时的fsimage文件,便于日后使用。
最终,主NameNode拥有最新的fsimage文件和一个更小的正在进行中的edits文件(edits文件可能非空,因为在创建检查点过程中主NameNode还可能收到一些编辑请求)。这个过程清晰解释了辅助NameNode和主NameNode拥有相近内存需求的原因(因为辅助NameNode也把fsimage文件载入内存)。因此,在大型集群中,辅助NameNode需要运行在一台专用机器上。
默认情况下,辅助NameNode每隔一个小时创建检查点;此外,如果从上一个检查点开始编辑日志的大小已经达到100万个事务时,即使不到一小时,也会创建检查点,检查频率为每分钟一次。
这个过程namesecondary目录发生了更新;secondaryNameNode的检查点目录的布局与NameNode的是相同的,这种设计的好处是NameNode发生故障时,可以从secondaryNameNode恢复数据;有两种实现方法:一是将相关存储目录复制到新的NameNode中;二是使用-importCheckpoint选项启动NameNode守护进程,从而将secondaryNameNode用作新的NameNode
与第一次开启hdfs过程不同的是此次有30多秒的安全模式: 在安全模式中在等待块报告,这也关系到DataNode的运行过程。
datanode(工作节点)
以块的形式进行存储数据
在HDFS中,我们真实的数据是由DataNode来负责来存储的,但是数据具体被存储到了哪个DataNode节点等元数据信息则是由我们的NameNode来存储的。
DataNode目录结构
和NameNode不同的是,DataNode的存储目录是初始阶段自动创建的,不需要额外格式化。DataNode的关键文件和目录如下所示:
分析:从上图可以看出,dataNode的文件结构主要由blk_前缀文件、BP-random integer-NameNode-IP address-creation time和VERSION构成。
- BP-random integer-NameNode-IP address-creation time :
- BP代表BlockPool的,就是Namenode的VERSION中的集群唯一blockpoolID
- 从上图可以看出我的DataNode是一个BP,也就是说只有一个NameNode管理全部的文件系统命名空间,如果有两个以上的BP,该HDFS是Federation HDFS,所以该目录下有两个BP开头的目录,IP部分和时间戳代表创建该BP的NameNode的IP地址和创建时间戳。
- finalized/rbw :
- 这两个目录都是用于实际存储HDFS BLOCK的数据,里面包含许多block_xx文件以及相应的.meta后缀的元数据文件,.meta文件包含了checksum信息。
- rbw是“replica being written”的意思,该目录用于存储用户当前正在写入的数据。
- blk_前缀文件 :
- HDFS中的文件块,存储的是原始文件内容。
- 块的元数据信息,每一个块有一个相关联的.meta文件,一个文件块由存储的原始文件字节组成。
- .meta文件包括头部(含版本和类型信息)和该块各区段的一系列的校验和。
- 每个块属于一个数据块池(在本篇文章中,只有一个数据块池),每个数据块池都有自己的存储目录,目录根据数据块池ID形成(和NameNode的VERSION文件中的数据块池ID相同)
注 :当目录中数据块的数量增加到一定规模时,DataNode会创建一个子目录来存放新的数据块及其元数据信息。如果当前目录已经存储了64个(通过dfs.datanode.numblocks属性设置)数据块时,就创建一个子目录。终极目标是设计一棵高扇出的目录树,即使文件系统中的块数量非常多,目录树的层数也不多。通过这种方式,DataNode可以有效管理各个目录中的文件,避免大多数操作系统遇到的管理难题,即很多(成千上万个)文件放在同一个目录之中。
- VERSION :
#Mon Sep 29 09:54:36 BST 2014storageID=DS-c478e76c-fe1b-44c8-ba45-4e4d6d266547
clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142
cTime=0
datanodeUuid=75ffabf0-813c-4798-9a91-e7b1a26ee6f1
storageType=DATA_NODE
layoutVersion=-57
- storageID :相对于DataNode来说是唯一的,用于在NameNode处标识DataNode
- clusterID :是系统生成或手动指定的集群ID
- cTime :表示NameNode存储时间的创建时间
- datanodeUuid :表示DataNode的ID号
- storageType :将这个目录标志位DataNode数据存储目录。
- layoutVersion :是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
-
in_use.lock : 是一个锁文件,NameNode使用该文件为存储目录加锁。可以避免其他NameNode实例同时使用(可能会破坏)同一个存储目录的情况。
数据块
每个磁盘都有默认的数据块大小,这是磁盘进行数据读/写的最小单位。构建于单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的块,该文件系统块的大小可以是磁盘块的整数倍。文件系统块一般为几千字节,而磁盘块一般为512字节。但这些对于需要读/写文件的文件系统用户来说是透明的。
HDFS同样也有块(block)的概念,但是大得多,默认为128MB。与单一磁盘上的文件系统相似,HDFS上的文件也被划分为块大小的多个分块,作为独立的存储单元。但与面向单一磁盘的文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间,例如当一个1MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB。
HDFS中的块为什么这么大?HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因为,传输一个由多个块组成的大文件的时间取决于磁盘传输速率。但是块大小这个参数也不会设置得过大,MapReduce中map任务通常一次只处理一个块中的数据,因此如果任务数太少(少于集群中的节点数量),作业的运行速度就会比较慢。
对分布式文件系统中的块进行抽象会带来很多好处。
- 第一好处是一个文件的大小可以大于网络中任意一个磁盘的容量。
- 第二个好处是使用抽象块而非整个文件作为存储单元,大大简化了存储子系统的设计。
- 第三个好处是块还非常适合用于数据备份进而提供数据容错能力和提高可用性。
HDFS将每个块复制到少数几个物理上相互独立的机器上(默认为3个),可以确保在块、磁盘或机器发生故障后数据不会丢失。如果发现一个块不可用,系统会从其他地方读取另一个复本,而这个过程对用户是透明的。一个因损坏或机器故障而丢失的块可以从其他候选地点复制到另一台可以正常运行的机器上,以保证复本的数量回到正常水平。同样,有些应用程序可能选择为一些常用的文件块设置更高的复本数量进而分散集群中的读取负载。
2.3 工作原理
写操作:
文件写入时:
Client向NameNode发起文件写入的请求。
NameNode根据文件大小和文件块配置情况,返回给Client它所管理部分DataNode的信息。
Client将文件划分为多个block块,并根据DataNode的地址信息,按顺序写入到每一个DataNode块中。
有一个文件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;发送过程是以流式写入。
流式写入过程,
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上的数据,放到其他节点去。读取时,要读其他节点去。
③挂掉一个节点,没关系,还有其他节点可以备份;甚至,挂掉某一个机架,也没关系;其他机架上,也有备份。
读操作:
当文件读取:
Client向NameNode发起文件读取的请求。
NameNode返回文件存储的block块信息、及其block块所在DataNode的信息。
Client读取文件信息。
读操作就简单一些了,如图所示,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。那么读取的时候,遵循的规律是:
优选读取本机架上的数据。
HDFS 数据备份
HDFS被设计成一个可以在大集群中、跨机器、可靠的存储海量数据的框架。它将所有文件存储成block块组成的序列,除了最后一个block块,所有的block块大小都是一样的。文件的所有block块都会因为容错而被复制。每个文件的block块大小和容错复制份数都是可配置的。容错复制份数可以在文件创建时配置,后期也可以修改。HDFS中的文件默认规则是write one(一次写、多次读)的,并且严格要求在任何时候只有一个writer。NameNode负责管理block块的复制,它周期性地接收集群中所有DataNode的心跳数据包和Blockreport。心跳包表示DataNode正常工作,Blockreport描述了该DataNode上所有的block组成的列表。
备份数据的存放:
备份数据的存放是HDFS可靠性和性能的关键。HDFS采用一种称为rack-aware的策略来决定备份数据的存放。通过一个称为Rack Awareness的过程,NameNode决定每个DataNode所属rack id。缺省情况下,一个block块会有三个备份,一个在NameNode指定的DataNode上,一个在指定DataNode非同一rack的DataNode上,一个在指定DataNode同一rack的DataNode上。这种策略综合考虑了同一rack失效、以及不同rack之间数据复制性能问题。
副本的选择:
为了降低整体的带宽消耗和读取延时,HDFS会尽量读取最近的副本。如果在同一个rack上有一个副本,那么就读该副本。如果一个HDFS集群跨越多个数据中心,那么将首先尝试读本地数据中心的副本。
安全模式:
系统启动后先进入安全模式,此时系统中的内容不允许修改和删除,直到安全模式结束。安全模式主要是为了启动检查各个DataNode上数据块的安全性。
2.3 HDFS中常用到的命令
1、hadoop fs
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
2、hadoop fsadmin
1 2 3 |
|
3、hadoop fsck
4、start-balancer.sh