共计 9916 个字符,预计需要花费 25 分钟才能阅读完成。
当某个数据集大大小超出单个物理机的存储能力时,我们可以考虑使用集群。管理跨网络机器存储的文件系统叫做分布式文件系统 (Distributed FileSystem)。随着多节点的引入,相应的问题也就出现了,例如其中最重要的一个问题就是如何保证在某个节点失败的情况下数据不会丢失。Hadoop 中有一个核心子项目 HDFS(Hadoop Distributed FileSystem) 就是用来管理集群的存储问题的,当然在 Hadoop 中不仅仅只能使用 HDFS,Hadoop 中有一个通用的抽象的文件系统概念,这样可以使 Hadoop 在不同种类的文件系统下运作,例如 Hadoop 可以与 Amazon 的 S3 文件系统集成起来一起使用。
1 HDFS 的设计理念
1.1 存储超大文件
这里的“超大文件”是指几百 MB、GB, 甚至 TB 级别的文件。
1.2 流式数据访问
HDFS 是建立在最有效的数据处理模式是一次写多次读(write-once,read-many-times)的模式的概念之上的,HDFS 存储的数据集作为 hadoop 的分析对象。在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。(流式读取最小化了硬盘的寻址开销,只需要寻址一次,然后就一直读啊读。硬盘的物理构造导致寻址开销的优化跟不上读取开销。所以流式读取更加适合硬盘的本身特性。当然大文件的特点也更适合流式读取。与流数据访问对应的是随机数据访问,它要求定位、查询或修改数据的延迟较小,比较适合于创建数据后再多次读写的情况,传统关系型数据库很符合这一点)
1.3 运行的硬件条件
运行在普通廉价的服务器上 HDFS 设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。
2 HDFS 不适合的场景
2.1 对数据访问要求低延迟的场景
由于 HDFS 是为高数据吞吐量应用而设计的,必然以高延迟为代价。
2.2 存储大量小文件
HDFS 中元数据(文件的基本信息)存储在 namenode 的内存中,而 namenode 为单点,小文件数量大到一定程度,namenode 内存就吃不消了。
2.3 多用户写入,任意修改文件
HDFS 中的文件可能只有一个 writer,而且写操作总是将数据添加在文件的末尾。她不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。
3 HDFS 的基本概念
3.1 block:块
每个磁盘都有一个数据块大小(blocksize),这是一次可以读取或写入数据的最小单位。HDFS 中也有数据块的概念,不过 HDFS 中的数据块却比一般磁盘的数据块(一般为 512Byte)大得多。像普通磁盘文件系统那样,HDFS 把文件分割成 block(下文如果没有特别声明,block 都是指 HDFS 中的 64MB 大小的 block)大小的数据块,并独立存储起来。不过与普通磁盘文件系统不同的是,如果一个文件比单个 block 小,这个文件并不会占用整个 block。
3.1.1 HDFS 为什么要使用大数据块
HDFS 中的数据块比普通磁盘文件系统要大得多,这么做的原因是最小化文件系统中数据寻址的时间。通过设置一个较大的 block 大小,寻址数据的时间就会比传输数据的时间小得多,从而处理一个大文件(HDFS 主要用来处理大数据的嘛)的时间就主要决定于数据传输的时间了。
如果数据寻址的时间平均为 10ms,而传输速率为 100MB/S,现在我们来大致计算一下,要想使数据寻址的时间只占到数据传输时间的 1%,那么我们需要设置每个 block 大小为 100MB。实际上默认的 block 大小为 64MB(很多 HDFS 的其他实现也使用 128MB)。以后 block 的大小还可能会随着数据传输速率的增加而增大。不过 block 的大小并不会一直增大下去。因为 MapReduce 中的 Map 任务每次只能处理一个 block,对于同样大小的一个文件,如果 block 太大从而使 maptask 太少的话,作业运行的时间反而会增加了。
3.1.2 在分布式文件系统层面又抽象出一个 block 的概念可以带来有以下好处
1. 由于没有一个文件必须存储在单个磁盘上的要求了,从而单个文件可以比集群中的任何一个节点的存储空间还要大,这样可以充分利用集群的存储能力。有可能(虽然不常见)一个文件会占用整个集群上所有节点的存储空间。
2. 以 block(而不是文件)作为抽象单元简化了存储子系统。简单是所有存储系统的共同目标,在发生故障方式多种多样的分布式文件系统中尤为重要。存储子系统只需要处理 block 就可以了,从而简化了存储管理(因为 block 是固定大小的,可以很容易的计算出某个磁盘最多可以存储多少个 block),而且还省去了元数据的管理负担(因为 block 只是需要存储的一串数据,文件的诸如访问权限之类的元数据不需要同 block 存储在一起,从而可以通过另一个系统 namenode 单独管理起来)。
3. 有了 block,提供数据容错和可用性的冗余备份(replication)机制可以更好的工作。在 HDFS 中,为了防止数据块损坏,或者磁盘及机器当机,每一个 block 在不同机器上都有几份备份(默认为 3)。如果一个 block 不能用了,HDFS 会以一种对用户透明的方式拷贝一份新的备份出来,从而把集群的数据安全级别恢复到以前的水平(你也可以通过提高冗余备份数来提高数据的安全级别)。
ps:
可以使用 HDFS 中的 fsck 命令在 block 层面交互,例如运行命令:
hadoop fsck / -files-blocks 会列出文件系统中组成所有文件的 blocks。
相关阅读:
Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm
Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm
Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm
Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm
单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm
搭建 Hadoop 环境(在 Winodws 环境下用虚拟机虚拟两个 Ubuntu 系统进行搭建)http://www.linuxidc.com/Linux/2011-12/48894.htm
更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13
2 namenode、datanode
HDFS 集群有两类节点,并以管理者 - 工作者模式运行,即一个 namenode(管理者)和多个 datanode(工作者)。namenode 管理文件系统的命名空间,它维护着整个文件系统树以及树中所有文件及目录的元数据。这些信息在本地文件系统中以两种形式永久保存:namespace image(包括 namespace 中所有文件的 inode 和 block 列表)和 editlog(记录了所有用户对 HDFS 所做的更改操作)。NameNode 也保存着构成给定文件的 blocks 的位置,但这些信息并不是永久保存在磁盘中的,因为这些信息是在系统启动时根据 datanode 的反馈信息重建、并且是定时基于 datanode 的报考更新的,具有很强的动态性。
客户端(client)代表用户(user)通过与 NameNode 和 DataNode 交互来访问文件系统。client 提供了一个类似 POSIX(PortableOperating SystemInterface,可移植操作系统接口)的文件系统接口,所以用户在编程中并不需要 namenode 和 datanode 的具体实现。
datanode 是文件系统的工作节点,它们根据需要存储并检索数据块(受客户端或 namenode 调度),并且定期向 namenode 发送它们所存储的块的列表。
namenode 是整个分布式文件系统的一个单点故障(single point of failure),没有了 namenode 整个分布式文件系统就无法使用了,因为我们无法从 blocks 中重构出相应的文件了。所以确保 namenode 能从失败中及时恢复是很重要的一件事,我们可以从以下两方面入手:
1. 第一种方法就是备份 namenode 中保存的永久信息(也就是上文中所提到的 namespaceimage 和 editlog),namenode 可以经过额外配置把它的永久信息保存到多个文件系统上去(这些多写操作是同步和原子性的)。最常用的做法是把永久信息保存到本地文件系统和某个远程 NFS(Network FileSystem)上去。
2. 另一种可能的做法就是运行一个 secondarynamenode,尽管它的名字跟 namenode 听起来差不多,但它的功能跟 namenode 却不一样。它最主要的工作就是把 namespaceimage 检查点文件与 editlog 相融合(以防止 editlog 过大)并把融合后的 namespaceimage 保存在自己的本地文件系统上,同时发送这个新的备份给 namenode。因为需要大量 CPU 资源和跟 namenode 一样大小内存的缘故,secondary namenode 通常运行在另一个单独的机器上。然后由于 secondarynamenode 上保存的状态信息总是要滞后于 namenode 上的状态信息的缘故(未融合的 editlog 记录了这一部分改变),如果 namenode 完全失败,数据肯定要丢失一部分。
3. 通常的做法是把上述两种方法结合起来,也即当 namenode 当机时,把远端 NFS 上的 namespace image 拷贝到 secondarynamenode 上,然后把 secondarynamenode 当做 namenode 来运行。
3 Hadoop Fedoration
namenode 在内存中保存着文件系统中每个文件和目录的引用,但集群规模扩大时,这便造成了一个瓶颈。于是在 hadoop2.x 发行版中引入了一个新的概念:Hadoop Fedoration。它允许集群拥有不止一个 namenode,这样每个 namenode 只负责维护文件系统中的一部分,例如一个 namenode 维护 /user 目录,另一个 namenode 可以维护 /share 目录。
在 fedoration 中,每个 namenode 维护两部分信息:1)由 namespace 元数据组成的 namespace volume;2)包含其负责维护的某一部分文件系统中的的所有文件的 block 位置信息的 block pool。namespace volume 各自之间是独立的,这就意味着 namenode 之间不用交互,而且某个 namenode 当机并不影响其他 namenode 的正常使用。相对于 namespace volume 而言,Block pool 并不是分区的,所以 datanodes 需要向集群中的每个 namenode 注册,并且可能要存储来自多个 blockpool 的数据。
要想使用带有 fedoration 特性的 cluster,用户可以使用用户端的挂载表来映射文件路径到 namenode。这个可以通过 ViewFileSystem 来配置,并使用 view fs://URI.
以下为 Fedoration 实现方式图解:
注解:
1. 多个 NN 共用一个集群里 DN 上的存储资源,每个 NN 都可以单独对外提供服务
2. 每个 NN 都会定义一个存储池,有单独的 id,每个 DN 都为所有存储池提供存储
3. DN 会按照存储池 id 向其对应的 NN 汇报块信息,同时,DN 会向所有 NN 汇报本地存储可用资源情况
4. 如果需要在客户端方便的访问若干个 NN 上的资源,可以使用客户端挂载表,把不同的目录映射到不同的 NN,但 NN 上必须存在相应的目录
这样设计的好处大致有:
1. 改动最小,向前兼容:
1)现有的 NN 无需任何配置改动.
2)如果现有的客户端只连某台 NN 的话,代码和配置也无需改动。
2. 分离命名空间管理和块存储管理:
1)提供良好扩展性的同时允许其他文件系统或应用直接使用块存储池
2)统一的块存储管理保证了资源利用率
3)可以只通过防火墙配置达到一定的文件访问隔离,而无需使用复杂的 Kerberos 认证
3. 客户端挂载表:
1)通过路径自动对应 NN
2)使 Federation 的配置改动对应用透明
当某个数据集大大小超出单个物理机的存储能力时,我们可以考虑使用集群。管理跨网络机器存储的文件系统叫做分布式文件系统 (Distributed FileSystem)。随着多节点的引入,相应的问题也就出现了,例如其中最重要的一个问题就是如何保证在某个节点失败的情况下数据不会丢失。Hadoop 中有一个核心子项目 HDFS(Hadoop Distributed FileSystem) 就是用来管理集群的存储问题的,当然在 Hadoop 中不仅仅只能使用 HDFS,Hadoop 中有一个通用的抽象的文件系统概念,这样可以使 Hadoop 在不同种类的文件系统下运作,例如 Hadoop 可以与 Amazon 的 S3 文件系统集成起来一起使用。
1 HDFS 的设计理念
1.1 存储超大文件
这里的“超大文件”是指几百 MB、GB, 甚至 TB 级别的文件。
1.2 流式数据访问
HDFS 是建立在最有效的数据处理模式是一次写多次读(write-once,read-many-times)的模式的概念之上的,HDFS 存储的数据集作为 hadoop 的分析对象。在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。(流式读取最小化了硬盘的寻址开销,只需要寻址一次,然后就一直读啊读。硬盘的物理构造导致寻址开销的优化跟不上读取开销。所以流式读取更加适合硬盘的本身特性。当然大文件的特点也更适合流式读取。与流数据访问对应的是随机数据访问,它要求定位、查询或修改数据的延迟较小,比较适合于创建数据后再多次读写的情况,传统关系型数据库很符合这一点)
1.3 运行的硬件条件
运行在普通廉价的服务器上 HDFS 设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。
2 HDFS 不适合的场景
2.1 对数据访问要求低延迟的场景
由于 HDFS 是为高数据吞吐量应用而设计的,必然以高延迟为代价。
2.2 存储大量小文件
HDFS 中元数据(文件的基本信息)存储在 namenode 的内存中,而 namenode 为单点,小文件数量大到一定程度,namenode 内存就吃不消了。
2.3 多用户写入,任意修改文件
HDFS 中的文件可能只有一个 writer,而且写操作总是将数据添加在文件的末尾。她不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。
3 HDFS 的基本概念
3.1 block:块
每个磁盘都有一个数据块大小(blocksize),这是一次可以读取或写入数据的最小单位。HDFS 中也有数据块的概念,不过 HDFS 中的数据块却比一般磁盘的数据块(一般为 512Byte)大得多。像普通磁盘文件系统那样,HDFS 把文件分割成 block(下文如果没有特别声明,block 都是指 HDFS 中的 64MB 大小的 block)大小的数据块,并独立存储起来。不过与普通磁盘文件系统不同的是,如果一个文件比单个 block 小,这个文件并不会占用整个 block。
3.1.1 HDFS 为什么要使用大数据块
HDFS 中的数据块比普通磁盘文件系统要大得多,这么做的原因是最小化文件系统中数据寻址的时间。通过设置一个较大的 block 大小,寻址数据的时间就会比传输数据的时间小得多,从而处理一个大文件(HDFS 主要用来处理大数据的嘛)的时间就主要决定于数据传输的时间了。
如果数据寻址的时间平均为 10ms,而传输速率为 100MB/S,现在我们来大致计算一下,要想使数据寻址的时间只占到数据传输时间的 1%,那么我们需要设置每个 block 大小为 100MB。实际上默认的 block 大小为 64MB(很多 HDFS 的其他实现也使用 128MB)。以后 block 的大小还可能会随着数据传输速率的增加而增大。不过 block 的大小并不会一直增大下去。因为 MapReduce 中的 Map 任务每次只能处理一个 block,对于同样大小的一个文件,如果 block 太大从而使 maptask 太少的话,作业运行的时间反而会增加了。
3.1.2 在分布式文件系统层面又抽象出一个 block 的概念可以带来有以下好处
1. 由于没有一个文件必须存储在单个磁盘上的要求了,从而单个文件可以比集群中的任何一个节点的存储空间还要大,这样可以充分利用集群的存储能力。有可能(虽然不常见)一个文件会占用整个集群上所有节点的存储空间。
2. 以 block(而不是文件)作为抽象单元简化了存储子系统。简单是所有存储系统的共同目标,在发生故障方式多种多样的分布式文件系统中尤为重要。存储子系统只需要处理 block 就可以了,从而简化了存储管理(因为 block 是固定大小的,可以很容易的计算出某个磁盘最多可以存储多少个 block),而且还省去了元数据的管理负担(因为 block 只是需要存储的一串数据,文件的诸如访问权限之类的元数据不需要同 block 存储在一起,从而可以通过另一个系统 namenode 单独管理起来)。
3. 有了 block,提供数据容错和可用性的冗余备份(replication)机制可以更好的工作。在 HDFS 中,为了防止数据块损坏,或者磁盘及机器当机,每一个 block 在不同机器上都有几份备份(默认为 3)。如果一个 block 不能用了,HDFS 会以一种对用户透明的方式拷贝一份新的备份出来,从而把集群的数据安全级别恢复到以前的水平(你也可以通过提高冗余备份数来提高数据的安全级别)。
ps:
可以使用 HDFS 中的 fsck 命令在 block 层面交互,例如运行命令:
hadoop fsck / -files-blocks 会列出文件系统中组成所有文件的 blocks。
相关阅读:
Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm
Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm
Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm
Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm
单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm
搭建 Hadoop 环境(在 Winodws 环境下用虚拟机虚拟两个 Ubuntu 系统进行搭建)http://www.linuxidc.com/Linux/2011-12/48894.htm
更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13
4 HDFS High-Availability
虽然通过在多个文件系统备份 namespace metadata 和使用 secondarynamenode 来定期合并 namespace image 和 editlog 以产生新的 checkpoint 可以保护集群以免数据丢失。但这并没有提供集群的高可用性,因为 namenode 本身仍然是一个单点故障——如果 namenode 当掉了,所有的客户端,包括 mapreduce 作业都无法正常读、写以及查看文件了,因为 namenode 是维护 namespace metadata 和提供 file-to-block 映射的唯一库。
4.1 从失败恢复需完成的工作
要想从失败的 namenode 中恢复,管理员应启动一个新的 namenode,同时配置 datanode 和用户使用这个新的 namenode。这个新的 namenode 暂时还不能正常运作,直到它做完了以下几件事:
1)把 namespace image 备份加载入内存;
2)重放 edit log 中的操作;
3)从 datanode 中接受足够的 blockreport(也就是记录各个 datanode 中 block 的信息以确定 file-to-block 映射),然后离开 safemode。
在有很多节点和文件的大的集群中,这个操作可能要花费几十分钟的时间!!
4.2 HDFS High-Availabilty
Hadoop2.x 发行版通过加入对 HDFS High-Availabilty 的支持而有效避免了长时间的 downtime。在这种实现中,有一对 namenode,它们分别配置为 active 和 standby。当 activenamenode 当掉时,standbynamenode 立即接手继续为 client 提供服务,期间的中断时间很小。为了实现 HDFS High-Availabilty,结构上发生了以下变化:
1)两个 namenode 使用一个高可用的共享设备(最初 HA 实现使用的是 NFS 来共享 editlog,不过在未来的版本中会提供更多的选项,如构建于 ZooKeeper 之上的基于 BookKeeper 的系统)来存储 editlog,当 standbynamenode 接手运行时,它就会立即重放 editlog 中的操作(同时它也充当着 secondarynamenode 的角色,不停地合并老的 namespaceimage 和新的 editlog 以免 editlog 过大),从而很快达到与 activenamenode 当掉前的状态。
2)datanode 需要向两个 namenode 发送 blockreport,因为 blockmapping 是存放在内存,而不是磁盘中的。
3)用户端(client)必须被合适配置并采用一种对用户透明的方式处理 namenode 的失败恢复。综合起来,如下图所示:
有了以上改变做基础,当 activenamenode 当掉时,因为 standynamenode 保存着最新的 edit log(同时还有上个检查点镜像文件)和最新的 block mapping,standynamenode 可以在几十秒内很快地接手继续工作。在实际应用中测得的失败恢复时间会长一些(大约一分钟左右),因为系统需要额外的时间确定 active namenode 确实已经当机了。
ps:edit.log 中都保存着哪些信息?
All mutations to the file system namespace,such as file renames, permission changes, file creations, blockallocations, etc, are written to a persistent write-ahead log bythe Name Node before returning success to a client call. Inaddition to this edit log, periodic checkpoints of the filesystem, called the fsimage, are also created and storedon-disk on the Name Node. Block locations, on the other hand,are stored only in memory. The locations of all blocks arereceived via“block reports”sent from the Data Nodes whenthe Name Node is started.
5 总结
HDFS 是 Apache Hadoop 的一个子项目,此文介绍了 HDFS 的一些基本知识,以及 Hadoop 2.x 引进的两个新特性 HDFS Fedoration 和 HDFS High Availability。后期将会深入到这两个特性的具体架构和实施、测试。