转载自:
https://cloud.tencent.com/developer/article/1031641
https://my.oschina.net/freelili/blog/1853668
HDFS优缺点
- 优点
- 1.1 高容错性
- 可以由数百或数千个服务器机器组成,每个服务器机器存储文件系统数据的一部分;
- 数据自动保存多个副本;
- 副本丢失后检测故障快速,自动恢复。
- 1.2 适合批处理
- 移动计算而非数据;
- 数据位置暴露给计算框架;
- 数据访问的高吞吐量;
- 运行的应用程序对其数据集进行流式访问。
- 1.3 适合大数据处理
- 典型文件大小为千兆字节到太字节;
- 支持单个实例中的数千万个文件;
- 10K+节点。
- 1.4 可构建在廉价的机器上
- 1.5 跨异构硬件和软件平台的可移植性强
- 1.6 简单一致性模型
- 应用程序需要一次写入多次读取文件的访问模型;
- 除了追加和截断之外,不需要更改已创建,写入和关闭的文件;
- 简化了数据一致性问题,并实现了高吞吐量数据访问;
- 高度可配置,具有非常适合于许多安装的默认配置。大多数时候,只需要为非常大的集群调整配置。
- 缺点
- 2.1 不适合低延迟的数据访问
- HDFS设计更多的是批处理,而不是用户交互使用。重点在于数据访问的高吞吐量,而不是数据访问的低延迟。
- 2.2 不适合小文件存取
- 占用NameNode大量内存;
- 寻道时间超过读取时间。
- 2.3 无法并发写入、文件随即修改
基本组成
- Namenode
- 接受客户端的读写服务
执行文件系统命名空间操作,如打开,关闭和重命名文件和目录。
- 管理文件系统命名空间
记录对文件系统命名空间或其属性的任何更改。
- 存储元数据信息—metadata
Metadata是存储在Namenode上的元数据信息,它存储到磁盘的文件名为:fsimage。并且有个叫edits的文件记录对metadata的操作日志。总体来说,fsimage与edits文件记录了Metadata中的权限信息和文件系统目录树、文件包含哪些块、确定块到DataNode的映射、Block存放在哪些DataNode上(由DataNode启动时上报)。
NameNode将这些信息加载到内存并进行拼装,就成为了一个完整的元数据信息。Namenode在内存中保存着整个文件系统的命名空间和文件数据块映射(Blockmap)的映像。这个关键的元数据结构设计得很紧凑,因而一个有4G内存的Namenode足够支撑大量的文件和目录。当Namenode启动时,它从硬盘中读取Edits和FsImage,将所有Edits中的事务作用在内存中的FsImage上,并将这个新版本的FsImage从内存中保存到本地磁盘上,然后删除旧的Edits,因为这个旧的Edits的事务都已经作用在FsImage上了。这个过程称为一个检查点(checkpoint)。
Datanode将HDFS数据以文件的形式存储在本地的文件系统中,它并不知道有关HDFS文件的信息。它把每个HDFS数据块存储在本地文件系统的一个单独的文件中。Datanode并不在同一个目录创建所有的文件,实际上,它用试探的方法来确定每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目录中支持大量的文件。当一个Datanode启动时,它会扫描本地文件系统,产生一个这些本地文件对应的所有HDFS数据块的列表,然后作为报告发送到Namenode,这个报告就是块状态报告。
- 管理文件系统命名空间
HDFS支持传统的分层文件组织。用户或应用程序可以在这些目录中创建目录和存储文件。文件系统命名空间层次结构与大多数其他现有文件系统类似:可以创建和删除文件,将文件从一个目录移动到另一个目录,或重命名文件。HDFS支持用户配额和访问权限。但不支持硬链接或软链接。
NameNode维护文件系统命名空间。对文件系统命名空间或其属性的任何更改由NameNode记录。应用程序可以指定应由HDFS维护的文件的副本数。文件的副本数称为该文件的复制因子。此信息由NameNode存储。
- SecondaryNameNode
它不是NameNode的备份,但可以作为NameNode的备份,当因为断电或服务器损坏的情况,可以用SecondNameNode中已合并的fsimage文件作为备份文件恢复到NameNode上,但是很有可能丢失掉在合并过程中新生成的edits信息。因此不是完全的备份。
由于NameNode仅在启动期间合并fsimage和edits文件,因此在繁忙的群集上,edits日志文件可能会随时间变得非常大。较大编辑文件的另一个副作用是下一次重新启动NameNode需要更长时间。SecondNameNode的主要功能是帮助NameNode合并edits和fsimage文件,从而减少NameNode启动时间。
- SNN执行合并时机
根据配置文件配置的时间间隔fs.checkpoint.period默认1小时;
dfs.namenode.checkpoint.txns
,默认设置为1百万,也就是Edits中的事务条数达到1百万就会触发一次合并,即使未达到检查点期间。 - SNN合并流程
snn合并流程.png
- 首先生成一个名叫edits.new的文件用于记录合并过程中产生的日志信息;
- 当触发到某一时机时(时间间隔达到1小时或Edits中的事务条数达到1百万)时SecondaryNamenode将edits文件、与fsimage文件从NameNode上读取到SecondNamenode上;
- 将edits文件与fsimage进行合并操作,合并成一个fsimage.ckpt文件;
- 将生成的合并后的文件fsimage.ckpt文件转换到NameNode上;
- 将fsimage.ckpt在NameNode上变成fsimage文件替换NameNode上原有的fsimage文件,并将edits.new文件上变成edits文件替换NameNode上原有的edits文件。
- SNN在hadoop2.x及以上版本在非高可用状态时还存在,但是在hadoop2.x及以上版本高可用状态下SNN就不存在了,在hadoop2.x及以上版本在高可用状态下,处于standby状态的NameNode来做合并操作。
- DataNode
管理附加到它们运行的节点的存储,并允许用户数据存储在文件中;
在内部,文件被分割成一个或多个块(Block),并且这些块被存储在一组DataNode中;
负责提供来自文件系统客户端的读取和写入请求;
执行块创建,删除;
启动DN进程的时候会向NN汇报Block信息;
通过向NN发送心跳保持与其联系(3秒一次),如果NN10分钟没有收到DN的心跳,则认为DN已经丢失,并且复制其上的Block到其他的DN上。
读写流程
hdfs读数据流程.jpg
- 使用HDFS提供的客户端Client, 通过 DistributedFileSystem 向远程的Namenode发起RPC请求;
- Namenode会视情况返回文件的部分或者全部block列表, 对于每个block, Namenode都会返回有该block副本的DataNode地址;
- 客户端Client会选取离客户端最近的DataNode来读取block; 如果客户端本身就是DataNode, 那么将从本地直接获取数据;
- 读取完当前block的数据后, 关闭当前的DataNode链接, 并为读取下一个block寻找最佳的DataNode;
- 当读完列表block后, 且文件读取还没有结束, 客户端会继续向Namenode获取下一批的block列表;
- 以上这些步骤对于客户端来说都是透明的。客户端只需通过 DistributedFileSystem 返回的 FSDataInputStream 读取数据即可
- 特别的--如果客户端和所连接的DataNode在读取时出现故障,那么它就会去尝试连接存储这个块的下一个最近的DataNode,同时它会记录这个节点的故障,以免后面再次连接该节点。客户端还会验证从DataNode传送过来的数据校验和。如果发现一个损坏块,那么客户端将再尝试从别的DataNode读取数据块,并且会告诉NameNode 这个信息,NameNode也会更新保存的文件信息,进行数据修复。
- 写数据流程
hdfs写流程.jpg
- 客户端调用create来新建文件。
- DistributedFileSystem 通过RPC调用在 NameNode 的文件系统命名空间中创建一个后缀是
.copy
新文件,此时还没有相关的DataNode与之相关。 - NameNode 会通过多种验证保证新的文件不存在文件系统中,并且确保请求客户端拥有创建文件的权限。当所有验证通过时,NameNode 会创建一个新文件的记录,如果创建失败,则抛出一个IOException异常;如果成功 namenode 能够掌握集群DataNode整体状况,并将第一批 block 块分配数据块后,连同 DataNode 列表信息返回给客户端;
- 当客户端写入数据时,DFSOutputStream 会将文件分割成数据包(64k),然后放入一个内部队列,我们称为“数据队列(data queue)”。DataStreamer会将这些小的文件包放入数据流中,DataStreamer的作用是请求NameNode为新的文件包分配合适的DataNode存放副本。返回的DataNode列表形成一个“管道”,假设这里的副本数是3,那么这个管道中就会有3个DataNode。DataStreamer将文件包以流的方式传送给队列中的第一个DataNode。第一个DataNode会存储这个包,然后将它推送到第二个DataNode中,随后照这样进行,直到管道中的最后一个DataNode,这种 pipeline 的方式加快了写入过程,并隐藏了副本数对客户端的影响,即 对客户端来说,副本数是透明的。
副本的放置遵循 Block的副本放置策略
- DFSOutputStream同时也会保存一个包的内部队列,用来等待管道中的DataNode返回确认信息,这个队列被称为确认队列(ask queue)。只有当所有的管道中的DataNode都返回了写入成功的信息文件包,才会从确认队列中删除。
- 客户端完成数据写入后,对数据流调用close方法。该操作将剩余的所有数据写入dataNode管线,当DataNode 向 NameNode 心跳汇报的时候,新写入的 block 信息被更新到 NameNode.第一批block 块的写入完成
- 重复以上过程,客户端继续第二批 block 块的写入,直至最后一批写入完成结束!
- 特别的--当出现写入某个DataNode失败时,HDFS会作出以下反应:
首先管道会被关闭,任何在 确认队列 中的文件包都会被添加到数据队列的前端,以确保故障节点下游的datanode不会漏掉任何一个数据包。
为存储在另一个正常的datanode的当前数据块指定一个新的标识,并将标识传送给nameNode,当dataNode 在恢复后,会发现其原来的标识是过时的,于是就可以删除存储的不完整的那部分数据块。
从管线中删除故障datanode,基于两个正常的datanode构建新的管线。余下的数据库写入管线中正常的datanode。
namenode在注意到副本不足时,会在另一个节点上创建一个新的副本。后续的数据块继续正常的接受处理。
如果有多个节点的写入失败了,如果满足了最小备份数的设置(
dfs.namenode.repliction.min
),写入也将会成功
- 写入一致性
新建一个文件后,它能够在文件系统命名空间中立即可见
写入文件的内容不保证立即可见(即逝数据流已经调用flush()方法刷新并存储)
当前正在写入的块对其他reader不可见。
通过hflush()方法后,数据被写入datanode的内存中。可保证对所有reader可见
通过hsync()方法后,数据被写入到磁盘上。
如果没有调用hflush或者hsync()方法。客户端在故障的情况下就会存在数据块丢失