赞
踩
大约在 15 年前,我们大数据开发的“祖师爷”(Doug Cutting)基于 Google 经典论文“三驾马车”,陆续实现了 HDFS、MapReduce、HBase 三个经典大数据组件并做了开源,这才有了这些年来大数据生态圈的红红火火。
所以开篇准备讲的就是这个最基础的也是最核心的,基于《Google File System》实现的 HDFS。它是一个可以部署在普通服务器上的分布式文件系统。那么,作为一个文件系统,因为有很多其他的应用是会基于它来设计存储结构的比如后面会提到的 HBase、Hive 等组件,所以它的稳定性、效率就变得至关重要了。
那么 HDFS 的底层是如何交互的,以及如何保证系统可用性的,看完这篇你就知道了。**
本篇面试内容划重点:ZKFC、JournalNode、读写、安全模式。
为了便于理解,举个简单的例子:我们可以把整个 HDFS 系统看作是动物园, 里面有许多嗷嗷待哺的小动物(DataNode),管理员们(Client)负责投喂和收餐盘(读写数据),但是动物太多,管理员没法准确知道需要去哪个位置投喂,所以需要有一个中转站,中转站里有一张记录小动物位置和种类信息(元数据信息)的表格(NameNode)放在固定的地方,投喂前管理员们都来中转站看一下表格,然后去找具体的位置。
表格的数据很重要,如果丢了管理员就会手足无措了,所以我们将表格再备份一份(Standby NameNode)放在抽屉里,每次数据修改都将数据同步到备份的表格处(JournalNode),如果主表格丢失了,监控(ZKFC)发现后保安(Zookeeper)立马把备份表格拿出来使用。
上面的例子帮助大家简单理了一下逻辑,下面进入正题,HDFS 进程还是比较多的,每个进程有各自的职责,然后按照既定的规则与其他进程交互,目的是维持系统正常稳定地运行。
另外,secondNameNode 由于会有单点问题已经很少应用,这里不讨论了,他的工作可以被 JournalNode 取代。
这些问题都是进程的职责相关的内容,答案都在上面的知识点中都有详细描述,问的方式有千千万万种,但是万变不离其宗,背后的知识点都是固定的。这里考察的是对 HDFS 组件比较常规的了解,各组件的职责和工作方式,重点需要掌握的是 ZKFC 和 JournalNode 的作用,不容有失。
为什么 Block 会从老版本的 64MB 升级到 128MB? 以前服务器的配置大多是 5400 转硬盘,平均读写理论上在 60-90MB/s,现在常用的是 7200 转,读写大致在 130-190MB/s。数据写磁盘是需要消耗寻址时间的,最优的理论情况是寻址时间仅占传输时间的 1%,为了降低寻址开销,最优情况当然是一次寻址写完这次传输的所有数据。
安全模式是 HDFS 处于初始化状态的一种自我保护机制,在这种模式下,HDFS 对于客户端来说是只读的。NameNode 主节点启动时,HDFS 就会进入安全模式。在安全模式中, DataNode 会向 NameNode 上报可用 Block 的信息,即告知 NameNode 当前集群中有哪些可用数据,因为 NameNode 初始时本身是不知道集群中有哪些 Block 的。
退出安全模式的条件?
数据读写流程在面试过程中是最常见的问题,答案其实很简单,但是想要答得出彩其实是不容易的,如这个知识点所描述的,从源码级别去看待这个读写流程,能看得更透彻,给面试官的印象也会更深刻。
首先 client 端通过在 DistributedFileSystem 上调用 create() 方法来创建一个文件。其中,DistributedFileSystem 是客户端用户创建的一个对象,用户可以通过调用 DistributedFileSystem 的方法来对 HDFS 做读写操作。
在收到 client 端 create 动作之后,DistributedFileSystem 通过 RPC 与 NameNode 通信 ,让它在文件系统的 namespace 上创建一个独立的新文件,NameNode 会确认文件是否已经存在以及客户端是否有权限。确认成功后,NameNode 会生成一条新文件的记录并返回一个负责 client 端与 datanode 和 namenode 进行 I/O 操作的 DFSOutputStream 对象给客户端,另外还会包含可写入的 DataNode 的信息。如文件创建失败,客户端会抛出一个 IOException。
当客户端开始写数据,DFSOutputStream 将文件分割成很多很小的块,然后将每个小块放进一个个 package 中, packages 会写进一个内部队列中,准备往 DataNode 写数据。
此时会根据 NameNode 返回的可写入的 DataNode 列表来构成一个 pipeline,默认是有三个 DataNode 组成, DataStreamer 将能够组成块的包先流入 pipeline 中的第一个 DataNode ,第一个 DataNode 会先存储来到的包,然后继续将所有的包转交到 pipeline 中的第二个 DataNode 中,以此类推。
DFSOutputStream 还维护了另一个确认队列,该队列等待 DataNode 的写入确认。当一个包已经被 pipeline 中的所有 DataNode 确认了写如磁盘成功,这个包才会从确认队列中移除。
当 Client 完成了数据写入,会在流上调用 close() 方法。需注意,这一步不是在 4 和 5 第一次完成之后,而是客户端需要写入的所有数据写完了之后。 这个行为会将所有剩下的包 flush 进 DataNode 中。
等到确认信息全部都到达,即步骤 5 完成之后,Client 会再次与 NameNode 通信告知完成。NameNode 会确认该文件的备份数是否满足要求。
之前提到了 HDFS 是由 DataNode,NameNode,JournalNode,DFSZKFailoverController 这些组件组成的,所以可用性会涉及到各个组件,面试时也要从多个方面来回答这个问题。
首先 NameNode 的高可用由 JournalNode 和 DFSZKFailoverController 保证,NameNode 有主备两个节点,JournalNode 负责主备节点数据的同步保证数据一致性,ZKFC 负责主备的 Failover,即主节点宕机由备用节点接替主节点工作。
JournalNode 也是分布式的,因为有选举机制,所以默认要大于一的奇数个服务器在线,同样是具有可用性保证的。
DFSZKFailoverController(ZKFC)是部署在两个 NameNode 节点上的独立的进程,他的作用是辅助 zookeeper 做 NameNode 的健康监控,保证异常切换,而 **Zookeeper **是一个独立的分布式系统,用于管理和协调分布式系统的工作,它本身也会通过 zab 协议来保证数据一致,和主备节点的选举切换等机制来保证可用性。
**DataNode **节点的宕机会造成部分 block 的丢失,但是 block 一般都会有三个备份,且在不同的 DataNode,所以 DataNode 挂掉两台仍然能保证数据的完整性,同时NameNode 会负责副本数的补充。
对于数据的可用性保证,HDFS 还提供了数据完整性校验的机制,当客户端创建 HDFS 文件时,它会计算文件的每个块的校验和(checknums),并存储在 NameNode 中。当客户端读文件时,会验证从每个 DataNode 接收的数据是否与 checknums 匹配。如果匹配失败,则证明数据已经损坏,此时客户端会选择从其他 DataNode 获取该块的其他可用副本。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。