HDFS架构[官网整理]
【HDFS Architecture(2.2+)】
HDFS是一个分布式文件系统,可以运行在廉价的商用机器上。它与现有的其他分布式文件系统有很多相似之处,当然也有很多不同之处。HDFS具有较高的容错性,适用于存储较大集合的数据,并能够支撑较高的吞吐能力。HDFS放宽了一些POSIX要求,以能够流式的访问数据。
一、硬件故障
硬件故障是常见的,而不是例外;一个HDFS集群或许有成百上千台机器构成,每台存储文件系统的一部分数据,事实上,一个集群有大量的组件,而且每个组件都有一定的故障概率,这也意味着总是会有一些组件无法正常工作,因此,故障检测和快速恢复它们,将是HDFS架构目标的核心。
二、流式数据访问
运行在HDFS之上的应用,需要流式访问它们的数据。HDFS更倾向于批量处理,而不是用户交互式操作;更偏重于数据访问的吞吐能力而不是延迟。POSIX有很多硬性要求,但是对HDFS的设计目标而言是不必要的,在一些关键点上,牺牲了POSIX原有的语义,以提高数据吞吐能力。
三、大数据集合
运行在HDFS上的应用,通常有较大的数据集合,一个文件的尺寸可达数GB,不过HDFS擅长于大文件存储。在一个集群中它需要提供较高的数据带宽和节点规模,它还需要支撑文件数以万计的文件。
四、简单的一致性模型
HDFS应用需要一次写入多次读取(write-once-read-many)的文件访问模型,一旦文件创建、写入数据、关闭后,它不需要再次修改,这种假设简化了数据一致性问题,而且在数据访问时有较高的吞吐能力。Map/Reduce应用或者web爬虫应用非常适合这种模式,我们将来计划支持对文件的appending-writes(2.2+已经支持)。
五、“Moveing Computation is Cheaper than Moving Data”
如果计算程序和它所需要的数据临近,那么执行效率将是更加高效的,即使当数据规模庞大时仍然一样。这可以最小化网络阻塞和提升系统整体的吞吐能力。迁移计算程序,让其临近所需数据,而不是将数据移动到计算程序的地方。HDFS提供大量的应用接口,移动移动计算程序让其临近数据。
六、Namenode与Datanodes
HDFS为master/slaves架构(不是严格意义上的M-S),HDFS集群包含一个Namanode,它作为master来管理文件系统的namespace和控制Client对文件的存取。此外,还有一定数量的Datanodes,一般为每个node一个,它们管理其上的数据存储;HDFS暴露文件系统的namespace,允许用户数据存储在文件中。其内部实现为,一个文件(HDFS File)被切分成多个blocks,这些blocks分别存在集群中的多个Datanodes。Namenodes执行一些文件系统namespace有关的操作,例如opening、closing、renaming文件或者目录;它还保存了blocks与Datanodes的映射(位置关系)。Datanodes的职责是服务于Client的read、write请求,它也根据Namenode的指令运行block的创建、删除、replication等。
Namode和Datanodes均可以运行在商用机器上,这些机器通常为LINUX系统,HDFS使用java语言构建,任何支持java平台的机器都可以运行Namenode和Datanodes,java语言的高移植性意味着HDFS可以大范围的部署。一个典型的部署方式,是Namenode部署在一个单独的机器上,其他的每个机器运行一个Datanode实例,不排除一台机器可以运行多个Datanodes,不过实际环境中我们很少这么做。
集群只有一个Namenode是大大简化了系统的架构,Namenode作为一个arbitrator负责HDFS的metadata(不保存实际文件数据),系统的这种设计,用户数据不会流经Namenode。
七、文件系统Namespace
HDFS支持传统的分级文件组织。应用程序可以创建目录,并将文件存储在这些目录中。文件系统的namespace层次和现有的文件系统类似;可以创建和删除文件,将文件在目录间移动,或者重命名文件。HDFS尚未完全实现用户配额(user Quotas)和访问权限。HDFS不支持hard links或者soft linkes,或许将来会实现。
Namenode维护文件系统的Namespace,nanespace的任何改动或者文件系统properties修改都会被namenodes记录。应用程序可以指定一个文件的replicas的个数,这个属性需要被HDFS保存。一个文件副本的个数,称之为“replication factor”,这个信息会保存在Namenode上。
八、Data Replication
HDFS被设计成在大规模集群中可靠的存储大文件数据。它将每个文件分割成一序列Blocks来存储;一个文件除最后一个block外(正在被写入),其他的所有的blocks文件尺寸都一样,这些blocks为容错(fault tolerance)都会被replicated。每个文件都可以配置各自的block大小和replication factor,应用程序可以为文件指定这些参数。“replication factor”可以在文件创建时指定,也可以在稍后修改(block size在文件创建后不能修改)。HDFS中的文件时write-once,而且任何时候只能有一个writer(Client端可以对一个文件并发的写,但是所有的写入数据都会队列化到一个Datanode的pipeline中,writer即为这个Datanode)。
在Block replicating时,所有的决定都有Namenode来做。它间歇性的从Datanodes接收heartbeat和Blockreport,以确定Datanodes运行良好。Blockreport包含Datanode上所有的blocks列表。
九、Replicas Placement
Replicas的放置是对HDFS可靠性和性能有重要影响。rack-aware放置策略的目的是提高数据的可靠性、可用性,以及带宽的利用。
大规模HDFS集群中,数据通常分布在不同rack上的多个机器上,不同rack上的两个nodes之间通信将会跨越多个switches,在多数情况下,同一个rack上的两个机器间的带宽比跨rack的两个机器带宽要高。
Namenode可以判断出每个Datanode所属的rack ID(参见Hadoop Rack Awareness)。一个简单而非最优的策略,就是将replicas放置在不同的rack上,当某个rack整体失效时可以避免丢失数据,而且可以在read数据时使用多个rack的带宽。这种策略将replicas在集群中均匀的分布,在组件失效时可以简单的实现balance load;不过这种策略,将会增加write数据的开支,因为write需要将blocks在多个rack间传输。
一般情况下,replication factor为3,HDFS replicas放置策略是将一个replica放在当前rack的一个node上,第二个replica放置在当前rack的另一个node上,第三个replica放置在其他rack的一个node上。这种策略降低了rack间write传输,提高了write的性能。rack失效的几率要远小于node的失效;这种策略不会影响数据的可靠性和可用性保证。不过,相对于三个不同的rack放置,它降低了read数据时整体带宽的使用。这种策略下,replicas没有均匀的在racks间分布。三分之一的replicas在一个node上,三分之二的replicas在另外的一个rack上。这种策略在没有影响数据可靠性和read性能的前提下,提高了write性能。
十、Replicas Selection
为了最小化全局的带宽消耗和read延迟,HDFS尽力将read请求读取离reader最近的replica。如果在reader节点所在的rack上存在replica,那么此replica将会优先选择。如果HDFS集群跨度多个data center,那么本地data center上的replicas将会比远端的data center优先。
十一、Safemode
在集群启动时,Namenode进入一个特殊的状态:safemode(安全模式)。在safemode时,blocks replcations不会发生。Namenode接收Datanodes的心跳和blockreport。blockreport包含当前Datanode持有的blocks列表。每个block都设定了最小replication个数,当Namenode接入了当前block最小个数的replication报告后,那么此block被认为是safely replicated。此后,当“safely replicated” blocks的个数达到了配置的百分比后(还有一个额外的30秒,参见dfs.namenode.safemode.extension),Namenode即可退出safemode。然后Namenode将那些blocks个数是否小于指定的“replicas个数”的blocks,在其他Datanodes上备份它们。
十二、文件系统Metada
HDFS namespace保存在namenode上。Namenode使用一种称为Editlog的transaction log持久保存文件系统的变更记录。例如,在HDFS上创建一个新文件将会导致Namenode在Editlog中插入一条记录来标识它。类似,修改一个文件的replication factor也会在Editlog中插入一条记录。Namenode使用操作系统文件系统的本地文件来存储Editlog。整个文件系统的namespace,包括文件与blocks映射关系,文件系统的属性(properties),保存在一个称为FsImage的文件中。Fsimage保存为namenode一个本地文件。
Namenode在内存中保存整个文件系统的namespace和blockmap(映射关系)。这些关键的metada设计紧凑,因此一个4G内存的Namenode可以支撑大量的文件和目录(的metadata)。当Namenode启动时,它会从磁盘读取Fsimage和Editlog,然后在内存中应用它们(重放),然后flush到磁盘生成一个新version的Fsimage文件。它可以删除那些旧的Editlog,因为Editlog中的transaction log已经应用并保存在了新的Fsiamge文件中;这个过程称为Checkpoint,checkpoint之后在Namenode启动时触发,将来可能会支持运行时间歇性的checkpoint。(参见backup node机制)
Datanodes将HDFS 数据保存在本地文件系统的文件中。Datanode对HDFS 文件并不知情(只关注block层面),它将HDFS block作为一个本地文件存储。Datanodes并不会在同一个目录下创建所有的本地文件,因为本地文件系统可能不会高效的支持在一个目录下存储巨大数量的本地文件(参见Block quota)。当Datanode启动时,它会扫描本地文件系统,整理出所有blocks的清单,并将此信息发送给Namenode,这就是Blockreport。
十三、交互协议
所有的HDFS交互协议都是基于TCP/IP协议的,Client使用配置的TCP地址和端口与Namenode建立链接,这称为ClientProtocol。Datanodes与Namenode通信使用DataNodeProtocol。
十四、健壮性
HDFS主要目的就是可靠的存储数据,即使有故障发生。三种常见的故障:Namenode失效,Datanode失效,网络分区(Network partitions)。
十五、磁盘故障、心跳和Re-replication
每个Datanode都间歇性的向Namenode发送心跳消息。网络分区可能会导致部分Datanodes与Namenode失去链接。Namenode能够通过心跳来检测到这种情况。Namenode将那些一段时间内没有发送心跳的Datanodes标记为“dead”,不会向它们转发任何IO请求;那些注册在Dead DataNodes上的数据也将不可用。DataNode死亡,将会导致部分blocks的replicas个数低于相应文件指定的“replication factor”。Namenode将会持续跟踪这些需要被replicated blocks,并在需要的时候re-replication。Re-replication的必要性有多种原因引起:一个Datanode不可用,一个replica损坏,一个Datanode上的某个磁盘失效,或者一个文件的replication factor提高。
十六、Reblancing
HDFS架构能够和数据rebalancing scheme相容。当一个Datanode上的磁盘剩余空间低于阀值时,将会把数据移动到其他Datanodes上。对于一个特定的文件,突然有较高的存储要求时(比如大批量数据写入),scheme将会动态的创建额外的replicas,以及在集群中rebalance。
十七、Data Integrity
从Datanode上获取的block可能在收到时已经损坏,这种损坏可能因为存储设备的故障、网络故障、或者软件的bug。HDFS Client实现了checksum来校验HDFS文件内容的完整性。当Client创建一个HDFS文件时,它会计算每个block的Checksum,然后把checksum值作为一个隐藏的文件存储在HDFS namespace中。当Client从每个Datanode接收到文件内容时,它将使用相应的checksum文件中的校验和值来校验。如果失败,Client将会尝试从其他Datanode上重新获取block replica(并会向Namenode报告block损坏)。
十八、Metadata磁盘故障
Fsimage和Editlog是HDFS的核心数据结构。这些文件的损坏将导致HDFS视力无法工作。因此,Namenode可以配置以支持维护多个fsimage和Editlog的备份。Fsimage或者Editlog的更新都会在各个备份间同步。这种同步更新可能降低namespace每秒事务量。不过,这个问题是可以接收的,毕竟HDFS是文件数据密集型,而不是metadata密集型。当Namenode启动时,它将使用最新的fsiamge和editlog恢复集群状态。
HDFS集群中,namenode机器有单点故障的问题。当Namenode故障失效,需要人工干预。当前自动重启和故障转移不支持。(2.2+已经支持,请参见HDFS HA与QJM)。
十九、snapshots
snapshot支持保存某一个时刻的数据备份。snapshot的一个使用场景为将一个损坏的HDFS实例回滚到上一个已知的良好的时间点上。HDFS目前对snapshot支持并不好。(尚无良好的手段基于snapshot对数据进行rollback)
二十、Data Blocks
HDFS被设计成支持大文件存储,当应用程序需要处理大数据时才会使用到HDFS。这些应用将数据write-once,并此后以流式访问数据。HDFS支持在文件上write-once-read-many。通常block尺寸为64M,那么HDFS将文件分割成64M的chunks,每个chunk可能会被放置在不同的Datanode上。
二十一、Staging(此段落内容可能与相应版本不符)
Client创建文件的请求不是立即到达Namenode。事实上,起初HDFS Client会将文件数缓存在本地的临时文件中,应用的写入操作透明地重定向到这个临时文件,当本地临时文件积累的数据达到了一个HDFS Block尺寸时,Client与Namenode交互。Namenode将文件名称写入到文件系统然后为它分配block(创建block标识),Namenode将Datanode的标识响应给Client,此后Client将本地临时文件传输给Datanode即可。然后Client关闭文件时再告知Namenode。此时,Namenode才会提交文件创建操作并持久保存,如果在文件closed之前Namenode失效,那么此文件将丢失。
经过认真考虑HDFS的目标应用后,采用了上述方式。这些应用需要流式写入文件。如果Client直接写入remote文件而不使用Client缓存的话,网络速度和阻塞将会很大程度上影响吞吐能力。这种方式并不是没有先例,早起的分布式文件系统,例如AFS也使用Client端缓存来提升性能。放宽了POSIX要求以达到较高的性能。
二十二、Replication Pipelining
当Client向HDFS文件写入数据时,数据首先写入本地文件,就像上述描述的那样。假如HDFS文件的relipcation factor为3,;当本地文件积累的数据达到一个block 尺寸时,Client将会从Namenode上获取一个Datanodes列表,这些Datanodes将会负责保存这个block replicas。Client此后将block刷新到第一个Datanode,此Datanode开始以小portion(4KB块,client分割)为单位接收数据,将每个portion写入本地库,然后将portion传输给Datanodes列表中的第二个Datanode,第二个Datanode也类似,将portion写入本地库,然后传输给第三个Datanode。最终,第三个Datanode也做同样的事情。就这样,一个Datanode能够从pipeline中的前一个Datanode接收数据,同时将数据局转发给pipeline中的下一个Datanode;Data最终以piplelined方式在Datanode间传递。
二十三、Accessibility
应用程序可以使用多种方式访问HDFS。HDFS本身为应用提供了FileSystem Java API使用。C语言也封装了相应的API。此外也支持HTTP方式,浏览器也可以访问HDFS系统。
二十四、FS Shell
HDFS提供了一些shell指令用于和系统交互,包括HDFS文件管理和系统管理(DFSAdmin)。请参见[hdfs常用指令]。
二十五、Space Reclamation(空间回收)
当一个文件被应用程序删除,它不会立即从HDFS中移除。而是,HDFS首先把它重命名(改变路径)到/trash目录(垃圾箱)。只要文件还在trash中,它都可以被迅速恢复。不过文件只会在trash中保留一定的时间(通过fs.trash.interval开启trash功能,并设定保留时长,默认此特性关闭),当过期后,HDFS才会真正删除文件(namespace中移除)。删除操作会导致相应的blocks所占空间被释放。不过,用户删除文件之后,可能需要一定的延迟后,HDFS才会释放磁盘空间。
当trash功能开启时,通过“hdfs dfs -rm”删除文件时,文件将会移动到trash目录(/user/root/.Trash/Current)。通过客户端API删除时也一样。我们也可以手动使用Trash类将文件移动到垃圾箱中。
只要文件存在trash目录中,用户即可撤销删除。/trash目录和普通的HDFS目录没有区别,如果想撤销删除,用户可以到此目录下,移动文件到其他目录即可。目前默认的策略是trash目录下文件被保存6个小时,此后将会被永久删除。
当一个文件的Replication factor降低,Namenode将会删除那些多余的replicas。此后将会通过心跳将操作信息反馈给Datanode,那么Datanode即可删除相应的block,并且释放存储空间。和上述一样,setReplication() API调用与实际的空间时间可能会有些延迟。