上篇讲到了HDFS的设计思想GFS,这篇接着讲HDFS架构。
HDFS全称为 Hadoop Distributed File System, 是 Hadoop 的分布式文件系统的实现。它的设计目标是存储海量数据,并为分布在网络中的大量客户端提供数据访问。HDFS的实现解决了存在于众多分布式文件系统(如 NFS)中大量的问题,具体来说,HDFS实现了以下问题:
- 能够保存非常大的数据量(TB级或PB级),HDFS的设计支持将数据散布在大量机器上,而且与其他分布式文件系统(如 NFS)相比,它支持更大的文件尺寸。
- 可靠地存储数据,为应对集群中单台机器的故障或不可访问,HDFS使用数据复制的方法。
- 为更好地与Hadoop的MapReduce集成,HDFS允许数据在本地读取并处理
HDFS为获得可扩展性和高性能而进行的的设计也是有代价的。HDFS只适用于特定类型的应用——它不是通用的分布式文件系统。大量额外的决策和取舍主导了HDFS的架构和实现,它们包括以下方面:
- HDFS 针对高速流式读取性能做了优化,随之而来的代价是降低了随机查找性能。 这意味着,如果应用程序需要从 HDFS 读取数据,那么应该避免查找,或者至少最 小化查找的次数。顺序读取是访问 HDFS 文件的首选方式。
- HDFS 仅支持一组有限的文件操作——写入、删除、追加和读取,不支持更新。它假定数据一次性写入HDFS,然后多次读取。
- HDFS 不提供本地数据缓存机制。缓存的开销非常大,以至于应该单纯地从源文件 重新读取数据,而这对于通常顺序读取大数据文件的应用程序来说并不是个问题。
HDFS系统架构如图
如上图:HDFS是主从结构,有一个主节点NameNode(名称节点)和多个从节点DataNode(数据节点)组成。HDFS 被实现为一种块结构的文件系统。HDFS中保存的是数据块,单个文件被拆分成固定大小的数据块,而这些数据块保存在 Hadoop 集群上的DataNode上。在Hadoop 1.x版本,数据块的大小是64兆,在Hadoop 2.x版本,数据块的大小是128兆。这样一来就有两个问:1.硬盘不够大,存放不了那么多数据块怎么办?这个简单,多加几个硬盘。2.数据只存放一份,万一这一份数据损坏了怎么办?为了解决数据不够安全的问题,HDFS实现了数据冗余,默认的冗余度是3。对于每个数据块来说,保存在哪个DataNode上是随机的,但这个数据块的其他冗余数据块保存在哪个DataNode上是通过机架感知决定的。至于什么是机架感知,可看下图:
rack1,rack2,rack3是三个不同的机架,每个机架里面存放的是若干台服务器,每个服务器就是一个DataNode,用来存放数据块。当有一个数据块需要存在HDFS中,会随机的选取一个机架,我们这里默认选择rack1,第一份数据块就保存在rack1中随机一个DataNode,万一rack1坏掉了,为了安全起见第二份数据块保存在除rack1外其他的机架上,为了查找数据块的效率,第三份数据块存放在与第一份数据块相同的机架rack1上。客户端只需要上传一份数据块即可,其他的冗余数据块是通过DataNode之间的水平复制达到冗余度的要求。
数据块存放到HDFS上,那么如何查找到数据块呢?HDFS采用倒排索引解决数据块的查找问题,什么是倒排索引,如图
看HDFS系统架构图,你可能会注意到,与NameNode并排的还有Secondary NameNode,HDFS集群有两类节点以管理者和工作者的工作模式运行,NameNode就是其中的管理者。它管理着文件系统的命名空间,维护着文件系统树及整棵树的所有文件和目录。这些信息以两个文件的形式保存于内存或者磁盘,这两个文件是:命名空间镜像文件fsimage和编辑日志文件edit logs ,同时NameNode也记录着每个文件中各个块所在的数据节点信息。
NameNode对元数据的处理过程如图:
图中有两个文件:
- fsimage:文件系统映射文件,也是元数据的镜像文件(磁盘中),存储某段时间NameNode内存元数据信息。
- edits log:操作日志文件。
- NameNode始终在内存中存储元数据(metedata),使得“读操作”更加快、
- 有“写请求”时,向edits文件写入日志,成功返回后才修改内存,并向客户端返回。
- fsimage文件为metedata的镜像,不会随时同步,与edits合并生成新的fsimage。
这就带来了一下问题:
- edits文件不断增大,如何存储和管理?
- 因为需要合并大量的edits文件生成fsimage,导致NameNode重启时间过长。
- 一旦NameNode宕机,用于恢复的fsiamge数据很旧,会造成大量数据的丢失
上述问题的解决方案就是运行Secondary NameNode,为主NameNode内存中的文件系统元数据创建检查点,Secondary NameNode所做的不过是在文件系统中设置一个检查点来帮助NameNode更好的工作。它不是要取代掉NameNode也不是NameNode的备份, SecondaryNameNode有两个作用,一是镜像备份,二是日志与镜像的定期合并。两个过程同时进行,称为checkpoint(检查点)。 镜像备份的作用:备份fsimage(fsimage是元数据发送检查点时写入文件); 日志与镜像的定期合并的作用:将NameNode中edits日志和fsimage合并,防止如果NameNode节点故障,NameNode下次启动的时候,会把fsimage加载到内存中,应用edits log,edits log往往很大,导致操作往往很耗时。(这也是namenode容错的一套机制)
Secondary NameNode创建检查点过程如图:
Secondarynamenode工作过程
- SecondaryNameNode通知NameNode准备提交edits文件,此时主节点将新的写操作数据记录到一个新的文件edits_inprogress中。
- SecondaryNameNode通过HTTP GET方式获取NameNode的fsimage与edits文件。
- SecondaryNameNode开始合并获取的上述两个文件,产生一个新的fsimage文件fsimage.check。
- SecondaryNameNode用HTTP POST方式发送fsimage.check至NameNode。
- NameNode将fsimage.check与edits_inprogress文件分别重命名为fsimage与edits,然后更新fstime,整个checkpoint过程到此结束。
SecondaryNameNode备份由三个参数控制fs.checkpoint.period控制周期(以秒为单位,默认3600秒),fs.checkpoint.size控制日志文件超过多少大小时合并(以字节为单位,默认64M), dfs.http.address表示http地址,这个参数在SecondaryNameNode为单独节点时需要设置。
从工作过程可以看出,SecondaryNameNode的重要作用是定期通过编辑日志文件合并命名空间镜像,以防止编辑日志文件过大。SecondaryNameNode一般要在另一台机器上运行,因为它需要占用大量的CPU时间与namenode相同容量的内存才可以进行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode发生故障时启用。