(一)HDFS简介
HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运用在廉价的商用服务器上。它所具备的,高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的的存储,为超大数据集的应用处理带来了很多便利。
HDFS架构由HDFSClient、NameNode、SecondaryNameNode、DataNode组成。
(二)HDFS的优缺点比较
HDFS的优点:
1.高容错性
(1)数据自动保存多个副本,并通过增加副本的形式,来提高容错性。默认是有三个副本,在默认情况下,每3秒钟,Datanode向Namenode报告自己的存活状态,如果一个Datenode超过十分钟还没有向Namenode报告自己的状态,那么namenode就会认为这个datenode节点已经“死亡”,然后会根据自己存储的信息,找到一个备份节点,将备份节点中的数据,拷贝到另外一台DataNode中,以此来实现多副本的形式。
block的副本放置策略:
第一个副本:放置在上传文件的DN上,如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。
第二个副本:放置在第一个副本不同的机架的节点上。
第三个副本:与第二个副本相同机架的不同节点上。
更多副本:随机节点。
2.适合做批处理
(1)它是通过移动计算而不是移动数据,就是说它会把整个业务逻辑根据Block块的位置,分配到不同的节点进行计算,然后将计算结果返回至客户端再由客户端去进行计算。这样就避免的大量的数据读写操作,并且由原来的一台计算变为现在的集群计算。
(2)它会把数据位置暴露给计算框架。
3.适合做大数据处理
(1)处理数据通常达到GB、TB甚至PB级别。
(2)能够处理百万规模以上的文件数量,数量相当之大。
(3)能够处理10k节点的规模。
4.流式文件访问
(1)一次写入,多次读取,文件一旦写入,只能追加,不能修改。因为HDFS通常用来做文件的存储,而不是文件的执行。
(2)能保证数据的一致性。
5.可构建在廉价机器上
(1)通过多副本机制,提高可靠性。
(2)它提供了容错和恢复机制,如果某个副本文件丢失,可以通过其他副本来恢复。
HDFS的缺点:
1.低延时数据访问
(1)它无法做到毫秒级的去存储数据
(2)它适合高吞吐率的场景,就是在某一个时间内写入大量数据,但无法做到毫秒级以内。
2.如果存储了大量的小文件的话,会占用NameNode大量的内存去存储文件、目录和块信息。而Namenode的内存是有限的。并且小文件的寻道时间都会超过读取时间,这就违反了HDFS的设计目标。
3.(1)一个文件只能有一个写,不允许多个线程同时写
(2)仅支持数据append(追加),不支持文件的随机修改
NameNode:
NameNode管理文件系统的命名空间:
1.文件和目录的元数据:
文件的block副本个数
修改和访问的时间
访问权限
block大小以及组成文件的block信息
2.以两种方式在Namenode本地进行持久化:
因为namenode的执行过程是在内存中,这就存在一个掉电易失的问题,所以通过镜像文件Fsimage和编辑日志(edits log)在内存中进行持久化。
3.fsimage不记录每个block所在的DateNode信息,这些信息在每次系统启动的时候从Datanode重建。之后Datenode会周期的通过心跳包向namenode报告block信息。DataNode向NameNode注册的时候,NameNode请求DataNode发送block列表信息。
在这里讲一下Hadoop的安全模式:
1.当我们开始启动一个集群的时候,会先启动NameNode,NameNode加载fsimage到内存,对内存数据执行edits.log日志中的事务操作。此时NameNode内存中已经恢复到上次关闭的状态了。
2.文件系统元数据在内存中的镜像加载完毕,这时候会进行fsimage和edits.log日志的合并,合并完成后会创建新的fsimage文件和一个空的edits.log日志文件,edits.log用于记录后续的操作。
3.NameNode等待DataNode上传的block列表信息,直到副本数满足“最小副本条件”(指整个文件系统中有99.9%的block达到了最小副本数,默认值是1 ,可以设置)。
4.当满足了最小副本条件,再过30秒,NameNode就会退出安全模式。
在安全模式下对文件进行只读操作,不允许进行文件的修改(写,删除或者重命名)
(注意事项)
Namenode不会持久化block位置信息,DateNode保有各自存储的block列表信息。在集群运行时,NameNode在内存中有一个block位置的映射信息。
NameNode在安全模式,NameNode需要给DataNode时间来上传block列表信息到NameNode。如果NameNode不等待DataNode上传这些信息的话,为了达到副本的数量,NameNode就会在DateNode之间进行block的复制,召唤出呢个资源的浪费,因为只需要等待DataNode上传自己存储的列表信息就可以了。
在安全模式下NameNode不会要求DataNode复制或者删除block。
新格式化的HDFS不进入安全模式,因为DataNode压根就没有block。
一个运行时的NameNode目录结构如下,该目录在第一次格式化的时候创建
有趣的是:如果属性dfs.namenode.name.dir指定了多个路径则每个路径中的内容都是一样的,也就是说这里我们可以将路径设定到别的机房中,那么当这个机房出问题时,别的机房的NameNode就可以保全下来。
in_use.lock文件用于NameNode锁定存储目录,这样就防止其他同事运行的NameNode实例使用相同的存储目录。
Version文件是一个Java的属性文件
layoutVersion是一个负数,定义了HDFS持久化数据结构的版本,这个版本数字跟hadoop版本无关。当layout,改变的时候,该数字减1(比如从-57到-58)。当对HDFDS进行了升级,就会发生layoutVersion的改变。
namespaceID是该文件系统的唯一标志符,当NameNode第一次格式化的时候生成。
clusterID是HDFS集群使用的一个唯一标志符,在HDFS联邦的情况下,就看出它的作用了,因为联邦情况下,集群有多个命名空间,不同的命名空间由不同的NameNode管理。
这里解释下,一个集群下的DataNode可能对应不止一个NameNode,几个NameNode都会往DateNode中存储数据,这时候,block块中的clusterID跟NameNode中的clusterID对应上,才算是属于一个集群下的数据。
blockpoolID是block池的唯一标志符,一个NameNode管理一个命名空间,该命名空间中的所有文件存储的block都在block池中。
cTime标记着当前NameNode创建的时间。对于刚格式化的存储,该值永远是0,但是当文件系统更新的时候,这个值就会更新为一个时间戳。
storageType表示当前目录存储NameNode内容的数据结构。
edits表示edits log日志文件
fsimage表示元数据镜像文件
NameNode在ch文件系统eckpoint之前首先要切换新的edits log文件,在切换时更新seen_txid的值。
当文件系统的客户端进行了写操作,这个事务首先会在edits.log中记录下来,而NameNode在内存中保存有文件系统的元数据,当edits.log记录结束后,就会更新内存中的元数据,然后内存中的元数据再去响应客户端的请求。
edits log在磁盘上表现为一定数量的文件。每个文件称为片段(Segment),前缀“edits”,后缀是其中包含的事务ID(transaction IDs)。每个写操作事务都仅仅打开一个文件(比如:edits_inprogress_00000000000010),写完后冲刷缓冲区并同步到磁盘,然后返回客户端success状态码。如果NameNode的元数据需要写到多个目录中,则对于每个写事务需要所有的写操作都完成,并冲刷缓冲区同步到磁盘才返回success状态码。这样就可以保证在发生宕机的时候没有事务数据丢失。
在这里解释下为什么不去直接修改fsimage,因为每个fsimage文件都是系统元数据的的一个完整的持久化检查点(checkpoint),而这样的镜像文件通常都是GB数量级的,磁盘的读写就要花费大量的时间。而edits.log只是一个文件,当有操作时,记录操作,然后进行追加,如果NameNode宕机,可以将最新fsimage加载进内存,同时执行edits.log对应于fsimage之后的操作,就可以重建元数据的状态。
2.SecondaryNameNode
这里有个问题,edits.log会随着对文件系统的操作而无限制的增长,这对正在运行的NameNode而言没有任何影响,但是一旦NameNode重新启动,那么edits.log所记录的海量操作数据就需要非常久的时间去完成fsimage的更新。而在这个期间,整个集群是不可以使用的。由此我们提出了SecondaryNameNode,它的作用就是为了NameNode内存中的文件系统元数据生成检查点。
工作流程如下:
1、secondarynamenode请求namenode生成新的edits log文件并向其中写日志。NameNode会在所有的存储目录中更新seen_txid文件
2、SecondaryNameNode通过HTTP GET的方式从NameNode下载fsimage和edits文件到本地。
3、SecondaryNameNode将fsimage加载到自己的内存,并根据edits log更新内存中的fsimage信息,然后将更新完毕之后的fsimage写到磁盘上。
4、SecondaryNameNode通过HTTP PUT将新的fsimage文件发送到NameNode,NameNode将该文件保存为.ckpt的临时文件备用。
5、NameNode重命名该临时文件并准备使用。此时NameNode拥有一个新的fsimage文件和一个新的很小的edits log文件(可能不是空的,因为在SecondaryNameNode合并期间可能对元数据进行了读写操作)。管理员也可以将NameNode置于safemode,通过hdfs dfsadmin -saveNamespace命令来进行edits log和fsimage的合并。
SecondaryNameNode要和NameNode拥有相同的内存。
对大的集群,SecondaryNameNode运行于一台专用的物理主机。
对于创建检查点(checkpoint)的过程,有三个参数进行配置:
1、默认情况下,SecondaryNameNode每个小时进行一次checkpoint合并
由dfs.namenode.checkpoint.period设置,单位秒
2、在不足一小时的情况下,如果edits log存储的事务达到了1000000个也进行一次checkpoint合并
由dfs.namenode.checkpoint.txns设置事务数量
3、事务数量检查默认每分钟进行一次
由dfs.namenode.checkpoint.check.period设置,单位秒。
SecondaryNameNode目录结构:
1、SecondaryNameNode中checkpoint目录布局(dfs.namenode.checkpoint.dir)和NameNode中的一样。
2、如果NameNode完全坏掉(没有备用机,也没有NFS),可以快速地从SecondaryNameNode恢复。
3、如果SecondaryNameNode直接接手NameNode的工作,需要在启动NameNode进程的时候添加
-importCheckpoint选项。该选项会让NameNode从由dfs.namenode.checkpoint.dir属性定义的路径中加载最新的checkpoint数据,但是为了防止元数据的覆盖,要求dfs.namenode.name.dir定义的目录中没有内容。
3.DataNode
DataNode不需要显式地格式化,关键文件和目录结构如下:
1、HDFS块数据存储于blk_前缀的文件中,包含了被存储文件原始字节数据的一部分。
2、每个block文件都有一个.meta后缀的元数据文件关联。该文件包含了一个版本和类型信息的头部,后接该block中每个部分的校验和。
3、每个block属于一个block池,每个block池有自己的存储目录,该目录名称就是该池子的ID(跟NameNode的VERSION文件中记录的block池ID一样)
当一个目录中的block达到64个(通过dfs.datanode.numblocks配置)的时候,DataNode会创建一个新的子目录来存放新的block和它们的元数据。这样即使当系统中有大量的block的时候,目录树也不会太深。同时也保证了在每个目录中文件的数量是可管理的,避免了多数操作系统都会碰到的单个目录中的文件个数限制(几十几百上千个)。
如果dfs.datanode.data.dir指定了位于在不同的硬盘驱动器上的多个不同的目录,则会通过轮询的方式向目录中写block数据(选择内存和CPU占用较少的节点)。block的副本不会存放在同一个DataNode上,而是存放在不同的DataNode节点之间。
DataNode存储数据模型:
1、文件线性切割成块(Block)
2、Block分散存储在集群节点中
3、单一文件Block大小一致,文件与文件可以不一致
4、Block可以设置副本数,副本分散在不同节点中
a) 副本数不要超过节点数量
b) 承担计算
5、文件上传可以设置Block大小和副本数
6、已上传的文件Block副本数可以调整,大小不变
7、只支持一次写入多次读取,同一时刻只有一个写入者
8、可以append追加数据