参考
分布式文件系统(DFS)
在传统的高性能集群中,计算节点和存储节点是各自独立的,它们之间通过高速网络完成互联,然而,在面临海量数据处理的问题时,网络必然会成为整个系统的性能瓶颈,这就需要引入超高速的网络如万兆以太网或Infiniband。然而,对大数场景来讲它们属于“奢侈品”,且昂贵的投入并不能带来网络性能的线性提升,因此性价比不高。面对这种问题,MapReduce采取了将计算节点与存储节点合二为一的集群模型,它利用分布式文件系统将数据存储于多个节点上,而后让处理过程在各数据节点本地直接进行,从而极大地降低了数据通过网络传送的需求。不过,这里仍然需要说明的是,MapReduce并非依赖于分布式文件系统,只不过运行在非分布式文件系统的MapReduce的诸多高级特性将无用武之地。
事实上,分布式文件系统并非MapReduce带来的新生事物,只不过,MapReduce站在前人的基础上将分布式文件系统进行了改造以使得它更能够适用于在MapReduce中完成海量数据处理。Google为在他们的MapReduce中实现的分布式文件系统为GFS(Google File System),而Hadoop的实现称作HDFS(Hadoop Distributed File System)。
HDFS的设计理念
HDFS专为存储大文件而设计,可运行于普通的商业服务器上,基于流式数据访问模型完成数据存取。HDFS将所有文件的元数据存储于名称节点(NameNode)的内存中,能够利用分布式特性高效地管理“大”文件(GB级别甚至更大的文件),对于有着海量小文件的应用场景则会给名称节点带去巨大压力并使得其成为系统性能瓶颈。再者,HDFS为MapReduce的计算框架而设计,存储下来数据主要用于后续的处理分析,其访问模型为“一次写入、多次读取”;因此,数据在HDFS中存储完成后,仅能在文件尾部附加新数据,而不能对文件进行修改。另外,HDFS专为了高效地传输大文件进行了优化,其为了完成此目标,在“低延迟”特性上做出了很大让步,因此,其不适用于较小访问延迟的应用。
HDFS架构
HDFS数据块
与传统文件系统一样,HDFS也在“块(block)”级别存取文件,所不同的是,传统文件系统数据块一般较小(1KB、2KB或4KB等),HDFS的数据块大小默认为64MB,甚至可以使用128MB或256MB级别的数据块。HDFS使用块抽象层管理文件,可以实现将分块分为多个逻辑部分后分布于多个存储节点,也能够有效简化存储子系统。而对于存储节点来说,较大的块可以减少磁盘的寻道次数,进而提升I/O性能。
名称节点(NameNode)和数据节点(DataNode)
HDFS集群中节点的工作模型为“master-worker”:其包含一个名称节点(master)和多个数据节点(worker)。
名称节点负责管理HDFS的名称空间,即以树状结构组织的目录及文件的元数据信息,这些信息持久存储于名称节点本地磁盘上并保存为名称空间镜像(namespace image)和编辑日志(edit log)两个文件。名称节点并不存储数据块,它仅需要知道每个文件对应数据块的存储位置,即真正存储了数据块的数据节点。然而,名称节点并不会持久存储数据块所与其存储位置的对应信息,因为这些信息是在HDFS集群启动由名称节点根据各数据节点发来的信息进行重建而来。这个重建过程被称为HDFS的安全模式。数据节点的主要任务包括根据名称节点或客户的要求完成存储或读取数据块,并周期性地将其保存的数据块相关信息报告给名称节点。
默认情况下,HDFS会在集群中为每个数据块存储三个副本以确保数据的可靠性、可用性及性能表现。在一个大规模集群中,这三个副本一般会保存至不同机架中的数据节点上以应付两种常见的故障:单数据节点故障和导致某机架上的所有主机离线的网络故障。另外,如前面MapReduce运行模型中所述,为数据块保存多个副本也有利于MapReduce在作业执行过程中透明地处理节点故障等,并为MapReduce中作业协同处理以提升性能提供了现实支撑。名称节点会根据数据节点的周期性报告来检查每个数据块的副本数是否符合要求,低于配置个数要求的将会对其进行补足,而多出的将会被丢弃。
HDFS提供了POSIX网络的访问接口,所有的数据操作对客户端程序都是透明的。当客户端程序需要访问HDFS中的数据时,它首先基于TCP/IP协议与名称节点监听的TCP端口建立连接,接着通过客户端协议(Client Protocol)发起读取文件的请求,而后名称节点根据用户请求返回相关文件的块标识符(blockid)及存储了此数据块的数据节点。接下来客户端向对应的数据节点监听的端口发起请求并取回所需要数据块。当需要存储文件并写数据时,客户端程序首先会向名称节点发起名称空间更新请求,名称节点检查用户的访问权限及文件是否已经存在,如果没有问题,名称空间会挑选一个合适的数据节点分配一个空闲数据块给客户端程序。客户端程序直接将要存储的数据发往对应的数据节点,在完成存储后,数据节点将根据名称节点的指示将数据块复制多个副本至其它节点。
名称节点的可用性
由前一节所述的过程可以得知,名称节点的宕机将会导致HDFS文件系统中的所有数据变为不可用,而如果名称节点上的名称空间镜像文件或编辑日志文件损坏的话,整个HDFS甚至将无从重建,所有数据都会丢失。因此,出于数据可用性、可靠性等目的,必须提供额外的机制以确保此类故障不会发生,Hadoop为此提供了两种解决方案。
最简单的方式是将名称节点上的持久元数据信息实时存储多个副本于不同的存储设备中。Hadoop的名称节点可以通过属性配置使用多个不同的名称空间存储设备,而名称节点对多个设备的写入操作是同步的。当名称节点故障时,可在一台新的物理主机上加载一份可用的名称空间镜像副本和编辑日志副本完成名称空间的重建。然而,根据编辑日志的大小及集群规模,这个重建过程可能需要很长时间。
另一种方式是提供第二名称节点(Secondary NameNode)。第二名称节点并不真正扮演名称节点角色,它的主要任务是周期性地将编辑日志合并至名称空间镜像文件中以免编辑日志变得过大。它运行在一个独立的物理主机上,并需要跟名称节点同样大的内存资源来完成文件合并。另外,它还保存一份名称空间镜像的副本。然而,根据其工作机制可知,第二名称节点要滞后于主节点,因此名称节点故障时,部分数据丢失仍然不可避免。
尽管上述两种机制可以最大程序上避免数据丢失,但其并不具有高可用的特性,名称节点依然是一个单点故障,因为其宕机后,所有的数据将不能够被访问,进而所有依赖于此HDFS运行的MapReduce作业也将中止。就算是备份了名称空间镜像和编辑日志,在一个新的主机上重建名称节点并完成接收来自各数据节点的块信息报告也需要很长的时间才能完成。在有些应用环境中,这可能是无法接受的,为此,Hadoop 0.23引入了名称节点的高可用机制——设置两个名称节点工作于“主备”模型,主节点故障时,其所有服务将立即转移至备用节点。进一步信息请参考官方手册。
在大规模的HDFS集群中,为了避免名称节点成为系统瓶颈,在Hadoop 0.23版本中引入了HDFS联邦(HDFS Federation)机制。HDFS联邦中,每个名称节点管理一个由名称空间元数据和包含了所有块相关信息的块池组成名称空间卷(namespace volume),各名称节点上的名称空间卷是互相隔离的,因此,一个名称节点的损坏并不影响其它名称节点继续提供服务。进一步信息请参考官方手册。