第三章 Hadoop分布式文件系统

第三章 Hadoop分布式文件系统

当数据集的大小超过一台独立的物理计算机的存储能力时,就有必要对它进行分区(partition)并存储到若干台单独的计算机上。管理网络中跨多台计算机存储的文件系统称为分布式文件系统(distributed filesystem)。该系统架构于网络之上,势必会引入网络编程的复杂性,因此分布式文件系统比普通磁盘文件系统更为复杂。例如,使文件系统能够容忍节点故障且不丢失任何数据,就是一个极大的挑战。

Hadoop自带一个称为HDFS的分布式文件系统,即 Hadoop Distributed Filesystem。

HDFS 以流式数据访问模式来存储超大文件,运行于商用硬件集群上。

  • 超大文件 “超大文件”在这里指具有几百MB、几百GB甚至几百TB大小的文件。
  • 流式数据访问 HDFS 的构建思路是这样的:一次写入、多次读取是最高效的访问模式。读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
  • 商用硬件 Hadoop并不需要运行在昂贵且可靠的硬件上。它是设计运行在商用硬件的集群上的,因此HDFS 被设计成在出现节点故障时能够继续运行且不让用户察觉到明显的中断。
  • 低时间延迟的数据访问 要求低时间延迟数据访问的应用,例如几十毫秒范围,不适合在HDFS上运行。记住,HDFS是为搞数据吞吐量应用优化的,这可能会以提高时间延迟为代价。
  • 大量的小文件 由于namenode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总数受限于namenode的内存总量。
  • 多用户写入,任意修改文件 HDFS 中的文件写入只支持单个写入者,而且写操作总是以“只添加”方式在文件末尾写数据。它不支持多个写入者的操作,也不支持在文件的任意位置进行修改。

数据块

每个磁盘都有默认的数据块大小,这是磁盘进行数据读/写的最小单位。构建于单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的块,该文件系统块的大小可以是磁盘块的整数倍。文件系统块一般为几千字节,而磁盘块一般为512字节。

HDFS 同样也有块(block)的概念,但是大得多,默认为128MB。与单一磁盘上的文件系统类似,HDFS上的文件也被划分为块大小的多个分块(chunk),作为独立的存储单元。但与面向单一磁盘的文件系统不同的是,HDFS 中小于一个块大小的文件不会占据整个块的空间(例如,当一个1 MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB)。

HDFS 中的块为什么这么大?
HDFS 的块比磁盘的块大,其目的是为了最小化寻址开销。如果块足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因而,传输一个由多个块组成的大文件的时间取决于磁盘传输速率。

对分布式文件系统中的块进行抽象会带来很多好处。第一个最明显的好处是,一个文件的大小可以大于网络中任意一个磁盘的容量。文件的所有块并不需要存储在同一个磁盘上,因此它们可以利用集群上的任意一个磁盘进行存储。

第二个好处是,使用抽象块而非整个文件作为存储单元,大大简化了存储子系统的设计。简化是所有系统的目标,但是这对于故障种类繁多的分布式系统来说尤为重要。块只是要存储的大块数据,而文件的元数据,如权限信息,并不需要与块一同存储,这样一来,其他系统就可以单独管理这些元数据。

不仅如此,块还非常适合用于数据备份进而提供数据容错能力和提高可用性。将每个块复制到少数几个物理上相互独立的机器上(默认为3个),可以确保在块、磁盘或机器发生故障后数据不会丢失。如果发现一个块不可用,系统会从其他地方读取另一个副本,而这个过程对于用户是透明的。一个因损坏或机器故障而丢失的块可以从其他候选地点复制到另一台可以正常运行的机器上,以保证副本的数量回到正常水平。同样,有些应用程序可能选择为一些常用的文件块设置更高的副本数量进而分散集群中的读取负载。

namenode和datanode

HDFS 集群有两类节点以管理节点-工作节点模式运行,即一个namenode(管理节点)和多个datanode(工作节点)。namenode管理文件系统的命名空间。它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。namenode也记录着每个文件中各个块所在的数据节点信息,但它并不永久保存块的位置信息,因为这些信息会在系统启动时根据数据节点信息重建。

客户端(client)代表用户通过与namenode和datanode交互来访问整个文件系统。客户端提供一个类似于POSIX(可移植操作系统界面)的文件系统接口,因此用户在编程时无需知道namenode和datanode也可实现其功能。

datanode是文件系统的工作节点。它们根据需要存储并检索数据块(受客户端或namenode调度),并且定期向namenode发送它们所存储的块的列表。

没有namenode,文件系统将无法使用。事实上,如果运行namenode服务的机器损坏,文件系统上所有的文件将会丢失,因为我们不知道如何根据datanode的块重建文件。因此对namenode实现容错非常重要,Hadoop为此提供两种机制。

第一种机制是备份那些组成文件系统元数据持久状态的文件。Hadoop可以通过配置使namenode在多个文件系统上保存元数据的持久状态。这种写操作是实时同步的,且是原子操作。一般的配置是,将持久状态写入本地磁盘的同时,写入一个远程挂载的网络文件系统(NFS)。

另一种可行的方法是运行一个辅助namenode,但它不能被用作namenode。这个辅助namenode的重要作用是定期合并编辑日志与命名空间镜像,以防止编辑日志过大。这个辅助namenode一般在另一台单独的物理计算机上运行,因为它需要占用大量CPU时间,并且需要与namenode一样多的内存来执行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode发生故障时启用。但是,辅助namenode保存的状态总是滞后于主节点,所以在主节点全部失效时,难免会丢失部分数据。在这种情况下,一般把存储在NFS上的namenode元数据复制到辅助namenode并作为新的主namenode运行。(注意,也可以运行热备份namenode代替运行辅助namenode)。

块缓存

通常datanode从磁盘中读取块,但对于访问频繁的文件,其对应的块可能被显示地缓存在datanode的内存中,以堆外块缓存(off-heap block cache)的形式存在。默认情况下,一个块仅缓存在一个datanode的内存中,当然可以针对每个文件配置datanode的数量。作业调度器(用于MapReduce、Spark和其他框架的)通过在缓存块的datanode上运行任务,可以利用块缓存的优势提高读操作的性能。例如,连接(join)操作中使用的一个小的查询表就是块缓存的一个很好的候选。

用户或应用通过在缓存池(cache pool)中增加一个cache directive 来告诉namenode需要缓存哪些文件及存多久。缓存池是一个用于管理缓存权限和资源使用的管理性分组。

联邦HDFS

namenode在内存中保存文件系统中每个文件和每个数据块的引用关系,这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。在2.x发行版本系列中引入的联邦HDFS允许系统通过添加namenode实现扩展,其中每个namenode管理文件命名空间中的一部分。例如,一个namenode可能管理 /usr 目录下的所有文件,而另一个namenode可能管理 /share 目录下的所有文件。

在联邦环境下,每个namenode维护一个命名空间卷(namespace volume),由命名空间的元数据和一个数据块池(block pool)组成,数据块池包含该命名空间下文件的所有数据块。命名空间卷之间是相互独立的,两两之间并不相互通信,甚至其中一个namenode的失效也不会影响由其他namenode维护的命名空间的可用性。数据块池不再进行拆分,因此集群中的datanode需要注册到每个namenode,并且存储着来自多个数据块池中的数据块。

HDFS 的高可用性

通过联合使用在多个文件系统中备份namenode的元数据和通过备用namenode创建监测点能防止数据丢失,但是依旧无法实现文件系统的高可用性。namenode依旧存在单点失效(SPOF,single point of failure)的问题。如果namenode失效了,那么所有的客户端,包括MapReduce作业,均无法读、写或列举(list)文件,因为namenode是唯一存储元数据与文件到数据块映射的地方。在这种情况下,Hadoop系统无法提供服务直到有新的namenode上线。

在这样的情况下,要想从一个失效的namenode恢复,系统管理员得启动一个拥有文件系统元数据副本的新的namenode,并配置datanode和客户端以便使用这个新的namenode。新的namenode直到满足以下情形才能响应服务:

  1. 将命名空间的映像导入内存中;
  2. 重演编辑日志;
  3. 接收到足够多的来自datanode的数据块报告并退出安全模式。对于一个大型并拥有大量文件和数据块的集群,namenode的冷启动需要30分钟,甚至更长时间。

系统恢复时间太长,也会影响到日常维护。事实上,预期之外的namenode失效出现概率很低,所以在现实中,计划内的系统失效时间实际更为重要。

Hadoop2 针对上述问题增加了对HDFS高可用性(HA)的支持。在这一实现中,配置了一对活动-备用(active-standby)namenode。当活动namenode失效,备用namenode就会接管它的任务并开始服务于来自客户端的请求,不会有任何明显中断。实现这一目标需要在架构上做如下修改:

  • namenode之间需要通过高可用共享存储实现编辑日志的共享。当备用namenode接管工作后,它将通读共享编辑日志直至末尾,以实现与活动namenode的状态同步,并继续读取由活动namenode写入的新条目。
  • datanode需要同时向两个namenode发送数据块处理报告,因为数据块的映射信息存储在namenode的内存中,而非磁盘。
  • 客户端需要使用特定的机制来处理namenode的失效问题,这一机制对用户是透明的。
  • 辅助namenode的角色被备用namenode所包含,备用namenode为活动的namenode命名空间设置周期性检查点。

可以从两种高可用性共享存储做出选择:NFS 过滤器或群体日志管理器(QJM,quorum journal manager)。QJM 是一个专用的HDFS实现,为提供一个高可用的编辑日志而设计,被推荐用于大多数HDFS部署中。QJM 以一组日志节点(journal node)的形式运行,每一次编辑必须写入多数日志节点。这种安排与ZK类似,但QJM 并没有使用ZK。(然而,HDFS HA在选取活动的namenode时确实使用了ZK)

在活动namenode失效之后,备用namenode能够快速(几十秒的时间)实现任务接管,因为最新的状态存储在内存中:包括最新的编辑日志条目和最新的数据块映射信息。实际观察到的失效时间略长一点(需要一分钟左右),这是因为系统需要保守确定活动namenode是否真的失效了。

在活动namenode 失效且备用namenode 也失效的情况下,当然这类情况发生的概率非常低,管理员依旧可以声明一个备用namenode 并实现冷启动。

故障的切换与规避

系统中有个称为故障转移控制器(failover controller)的新实体,管理着将活动namenode转移为备用namenode的转换过程。有多种故障转移控制器,但默认的一种是使用了ZK来确保有且仅有一个活动namenode。每一个namenode运行着一个轻量级的故障转移控制器,其工作就是监视宿主namenode是否失效(通过一个简单的心跳机制实现)并在namenode失效时进行故障切换。

管理员也可以手动发起故障转移,例如日常维护。这称为“平稳的故障转移”(graceful failover),因为故障转移控制器可以组织两个namenode有序地切换角色。

同一时间QJM仅允许一个namenode向编辑日志写入数据。而NFS过滤器没有这个限制(这也是为什么推荐QJM的原因)。当失效namenode因为网络原因无法知道其是否停止运行时,对于失效的namenode而言,它仍有可能响应并处理客户过时的请求。高可用实现做了进一步的优化,以确保先前活动的namenode不会执行危害系统的操作,该方法称为“规避”(fencing)。规避机制包括:设置一个SSH命令用于杀死namenode、撤销namenode访问共享存储目录的权限、通过远程命令屏蔽网络端口。最后还有“一枪爆头”STONITH,shoot in the head的技术进行规避,该方法主要通过一个特定的供电单元对相应的主机进行断电操作。

访问Hadoop

Hadoop 以Java API的形式提供文件系统的访问接口,非Java 开发的应用访问HDFS 会很不方便。由WebHDFS协议提供的HTTP REST API 则使得其他语言开发的应用能够方便地与HDFS 交互。注意,HTTP 接口比原生的Java客户端要慢,所以尽量不要用它来传输特大数据。

通过 HTTP 来访问HDFS 有两种方法:直接访问;通过代理访问。通常情况下都通过代理访问访问HDFS。httpfs.sh 脚本可以启动独立于namenode和datanode的守护进程(默认在一个不同的端口上监听),提供和WebHDFS相同的 HTTP 接口。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值