当某个数据集大大小超出单个物理机的存储能力时,我们可以考虑使用集群。管理跨网络机器存储的文件系统叫做分布式文件系统(Distributed FileSystem)。随着多节点的引入,相应的问题也就出现了,例如其中最重要的一个问题就是如何保证在某个节点失败的情况下数据不会丢失。Hadoop中有一个核心子项目HDFS(Hadoop Distributed FileSystem)就是用来管理集群的存储问题的,当然在Hadoop中不仅仅只能使用HDFS,Hadoop中有一个通用的抽象的文件系统概念,这样可以使Hadoop在不同种类的文件系统下运作,例如Hadoop可以与Amazon的S3文件系统集成起来一起使用。
1 HDFS的设计理念
1.1 存储超大文件
这里的“超大文件”是指几百MB、GB,甚至TB级别的文件。
1.2 流式数据访问
HDFS是建立在最有效的数据处理模式是一次写多次读(write-once,read-many-times)的模式的概念之上的,HDFS存储的数据集作为hadoop的分析对象。在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。(流式读取最小化了硬盘的寻址开销,只需要寻址一次,然后就一直读啊读。硬盘的物理构造导致寻址开销的优化跟不上读取开销。所以流式读取更加适合硬盘的本身特性。当然大文件的特点也更适合流式读取。与流数据访问对应的是随机数据访问,它要求定位、查询或修改数据的延迟较小,比较适合于创建数据后再多次读写的情况,传统关系型数据库很符合这一点)
1.3 运行的硬件条件
运行在普通廉价的服务器上HDFS设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。
2 HDFS不适合的场景
2.1 对数据访问要求低延迟的场景
由于HDFS是为高数据吞吐量应用而设计的,必然以高延迟为代价。
2.2 存储大量小文件
HDFS中元数据(文件的基本信息)存储在namenode的内存中,而namenode为单点,小文件数量大到一定程度,namenode内存就吃不消了。
2.3 多用户写入,任意修改文件
HDFS中的文件可能只有一个writer,而且写操作总是将数据添加在文件的末尾。她不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。
3 HDFS的基本概念
3.1 block:块
每个磁盘都有一个数据块大小(blocksize),这是一次可以读取或写入数据的最小单位。HDFS中也有数据块的概念,不过HDFS中的数据块却比一般磁盘的数据块(一般为512Byte)大得多。像普通磁盘文件系统那样,HDFS把文件分割成block(下文如果没有特别声明,block都是指HDFS中的64MB大小的block)大小的数据块,并独立存储起来。不过与普通磁盘文件系统不同的是,如果一个文件比单个block小,这个文件并不会占用整个block。
3.1.1 HDFS为什么要使用大数据块
HDFS中的数据块比普通磁盘文件系统要大得多,这么做的原因是最小化文件系统中数据寻址的时间。通过设置一个较大的block大小,寻址数据的时间就会比传输数据的时间小得多,从而处理一个大文件(HDFS主要用来处理大数据的嘛)的时间就主要决定于数据传输的时间了。
如果数据寻址的时间平均为10ms,而传输速率为100MB/S,现在我们来大致计算一下,要想使数据寻址的时间只占到数据传输时间的1%,那么我们需要设置每个block大小为100MB。实际上默认的block大小为64MB(很多HDFS的其他实现也使用128MB)。以后block的大小还可能会随着数据传输速率的增加而增大。不过block的大小并不会一直增大下去。因为MapReduce中的Map任务每次只能处理一个block,对于同样大小的一个文件,如果block太大从而使maptask太少的话,作业运行的时间反而会增加了。
3.1.2 在分布式文件系统层面又抽象出一个block的概念可以带来有以下好处
1. 由于没有一个文件必须存储在单个磁盘上的要求了,从而单个文件可以比集群中的任何一个节点的存储空间还要大,这样可以充分利用集群的存储能力。有可能(虽然不常见)一个文件会占用整个集群上所有节点的存储空间。
2. 以block(而不是文件)作为抽象单元简化了存储子系统。简单是所有存储系统的共同目标,在发生故障方式多种多样的分布式文件系统中尤为重要。存储子系统只需要处理block就可以了,从而简化了存储管理(因为block是固定大小的,可以很容易的计算出某个磁盘最多可以存储多少个block),而且还省去了元数据的管理负担(因为block只是需要存储的一串数据,文件的诸如访问权限之类的元数据不需要同block存储在一起,从而可以通过另一个系统namenode单独管理起来)。
3. 有了block,提供数据容错和可用性的冗余备份(replication)机制可以更好的工作。在HDFS中,为了防止数据块损坏,或者磁盘及机器当机,每一个block在不同机器上都有几份备份(默认为3)。如果一个block不能用了,HDFS会以一种对用户透明的方式拷贝一份新的备份出来,从而把集群的数据安全级别恢复到以前的水平(你也可以通过提高冗余备份数来提高数据的安全级别)。
ps:
可以使用HDFS中的fsck命令在block层面交互,例如运行命令:
hadoop fsck / -files-blocks 会列出文件系统中组成所有文件的blocks。
2 namenode、datanode
HDFS集群有两类节点,并以管理者-工作者模式运行,即一个namenode(管理者)和多个datanode(工作者)。namenode管理文件系统的命名空间,它维护着整个文件系统树以及树中所有文件及目录的元数据。这些信息在本地文件系统中以两种形式永久保存:namespace p_w_picpath(包括namespace中所有文件的inode和block列表)和editlog(记录了所有用户对HDFS所做的更改操作)。NameNode也保存着构成给定文件的blocks的位置,但这些信息并不是永久保存在磁盘中的,因为这些信息是在系统启动时根据datanode的反馈信息重建、并且是定时基于datanode的报考更新的,具有很强的动态性。
客户端(client)代表用户(user)通过与NameNode和DataNode交互来访问文件系统。client提供了一个类似POSIX(PortableOperating SystemInterface,可移植操作系统接口)的文件系统接口,所以用户在编程中并不需要namenode和datanode的具体实现。
datanode是文件系统的工作节点,它们根据需要存储并检索数据块(受客户端或namenode调度),并且定期向namenode发送它们所存储的块的列表。
namenode是整个分布式文件系统的一个单点故障(single point of failure),没有了namenode整个分布式文件系统就无法使用了,因为我们无法从blocks中重构出相应的文件了。所以确保namenode能从失败中及时恢复是很重要的一件事,我们可以从以下两方面入手:
1. 第一种方法就是备份namenode中保存的永久信息(也就是上文中所提到的namespacep_w_picpath和editlog),namenode可以经过额外配置把它的永久信息保存到多个文件系统上去(这些多写操作是同步和原子性的)。最常用的做法是把永久信息保存到本地文件系统和某个远程NFS(Network FileSystem)上去。
2.另一种可能的做法就是运行一个secondarynamenode,尽管它的名字跟namenode听起来差不多,但它的功能跟namenode却不一样。它最主要的工作就是把namespacep_w_picpath检查点文件与editlog相融合(以防止editlog过大)并把融合后的namespacep_w_picpath保存在自己的本地文件系统上,同时发送这个新的备份给namenode。因为需要大量CPU资源和跟namenode一样大小内存的缘故,secondary namenode通常运行在另一个单独的机器上。然后由于secondarynamenode上保存的状态信息总是要滞后于namenode上的状态信息的缘故(未融合的editlog记录了这一部分改变),如果namenode完全失败,数据肯定要丢失一部分。
3. 通常的做法是把上述两种方法结合起来,也即当namenode当机时,把远端NFS上的namespace p_w_picpath拷贝到secondarynamenode上,然后把secondarynamenode当做namenode来运行。
3 Hadoop Fedoration
namenode在内存中保存着文件系统中每个文件和目录的引用,但集群规模扩大时,这便造成了一个瓶颈。于是在hadoop2.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注册,并且可能要存储来自多个blockpool的数据。
要想使用带有fedoration特性的cluster,用户可以使用用户端的挂载表来映射文件路径到namenode。这个可以通过ViewFileSystem来配置,并使用view fs://URI.
注解:
1. 多个NN共用一个集群里DN上的存储资源,每个NN都可以单独对外提供服务
2. 每个NN都会定义一个存储池,有单独的id,每个DN都为所有存储池提供存储
3. DN会按照存储池id向其对应的NN汇报块信息,同时,DN会向所有NN汇报本地存储可用资源情况
4. 如果需要在客户端方便的访问若干个NN上的资源,可以使用客户端挂载表,把不同的目录映射到不同的NN,但NN上必须存在相应的目录
这样设计的好处大致有:
1. 改动最小,向前兼容 :
1)现有的NN无需任何配置改动.
2)如果现有的客户端只连某台NN的话,代码和配置也无需改动。
2. 分离命名空间管理和块存储管理 :
1)提供良好扩展性的同时允许其他文件系统或应用直接使用块存储池
2)统一的块存储管理保证了资源利用率
3)可以只通过防火墙配置达到一定的文件访问隔离,而无需使用复杂的Kerberos认证
3. 客户端挂载表:
1)通过路径自动对应NN
2)使Federation的配置改动对应用透明
4 HDFS High-Availability
虽然通过在多个文件系统备份namespace metadata和使用secondarynamenode来定期合并namespace p_w_picpath和editlog以产生新的checkpoint可以保护集群以免数据丢失。但这并没有提供集群的高可用性,因为namenode本身仍然是一个单点故障——如果namenode当掉了,所有的客户端,包括mapreduce作业都无法正常读、写以及查看文件了,因为namenode是维护namespace metadata和提供file-to-block映射的唯一库。
4.1 从失败恢复需完成的工作
要想从失败的namenode中恢复,管理员应启动一个新的namenode,同时配置datanode和用户使用这个新的namenode。这个新的namenode暂时还不能正常运作,直到它做完了以下几件事:
1)把namespace p_w_picpath备份加载入内存;
2)重放edit log中的操作;
3)从datanode中接受足够的blockreport(也就是记录各个datanode中block的信息以确定file-to-block映射),然后离开safemode。
在有很多节点和文件的大的集群中,这个操作可能要花费几十分钟的时间!!
4.2 HDFS High-Availabilty
Hadoop2.x发行版通过加入对HDFS High-Availabilty的支持而有效避免了长时间的downtime。在这种实现中,有一对namenode,它们分别配置为active和standby。当activenamenode当掉时,standbynamenode立即接手继续为client提供服务,期间的中断时间很小。为了实现HDFS High-Availabilty,结构上发生了以下变化:
1)两个namenode使用一个高可用的共享设备(最初HA实现使用的是NFS来共享editlog,不过在未来的版本中会提供更多的选项,如构建于ZooKeeper之上的基于BookKeeper的系统)来存储editlog,当standbynamenode接手运行时,它就会立即重放editlog中的操作(同时它也充当着secondarynamenode的角色,不停地合并老的namespacep_w_picpath和新的editlog以免editlog过大),从而很快达到与activenamenode当掉前的状态。
2)datanode需要向两个namenode发送blockreport,因为blockmapping是存放在内存,而不是磁盘中的。
3)用户端(client)必须被合适配置并采用一种对用户透明的方式处理namenode的失败恢复。综合起来,如下图所示:
有了以上改变做基础,当activenamenode当掉时,因为standynamenode保存着最新的edit log(同时还有上个检查点镜像文件)和最新的block mapping,standynamenode可以在几十秒内很快地接手继续工作。在实际应用中测得的失败恢复时间会长一些(大约一分钟左右),因为系统需要额外的时间确定active namenode确实已经当机了。
ps:edit.log中都保存着哪些信息?
All mutations to the file system namespace,such as file renames, permission changes, file creations, blockallocations, etc, are written to a persistent write-ahead log bythe Name Node before returning success to a client call. Inaddition to this edit log, periodic checkpoints of the filesystem, called the fsp_w_picpath, are also created and storedon-disk on the Name Node. Block locations, on the other hand,are stored only in memory. The locations of all blocks arereceived via “block reports” sent from the Data Nodes whenthe Name Node is started.
5 总结
HDFS是Apache Hadoop的一个子项目,此文介绍了HDFS的一些基本知识,以及Hadoop 2.x引进的两个新特性HDFS Fedoration和HDFS High Availability。后期将会深入到这两个特性的具体架构和实施、测试。
—— Rango Chen