Hadoop读书笔记(一)——Hadoop分布式文件系统

来源:互联网 发布:模架编程培训要多久 编辑:程序博客网 时间:2024/05/21 10:28

当数据集的大小超过一台独立的物理计算机的存储能力时,就有必要对它进行分区(partition)并存储到若干单独的计算机上。管理网络中跨多台计算机存储的文件系统称为分布式文件系统(distributed filesystem)。


1.1 HDFS设计

HDFS以流式数据访问模式来存储超大文件,运用于商用集群上。具体描述如下:

超大文件:目前已有PB级数据。

流式数据访问:一次写入,多次读取。数据集通常由数据源生成或从数据源复制而来,接着长时间在此数据集上进行各种分析。每次分析都将涉及该数据集的大部分数据甚至全部,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。

商用硬件:Hadoop并不需要运行在昂贵且搞可靠的硬件上。它是运行在商用硬件的集群上的,因此至少对于庞大的集群来说,节点故障的几率还是非常高的。HDFS遇到上述故障时,被设计成能够继续运行且不让用户察觉到明显的中断。

低时间延迟的数据访问:要求低时间延迟数据访问的应用,不适合在HDFS上运行。HDFS是为搞数据吞吐量应用优化的,这可能会以提高时间延迟为代价。目前,对于低延迟的访问需求,HBase是更好的选择。

大量的小文件:由于namenode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总数受限于namenode的内存容量。

多用户写入,任意修改文件:HDFS中的文件可能只有一个writer,而且写操作总是将数据添加在文件的末尾。它不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。


1.2 HDFS的概念

1.2.1 数据块

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

HDFS同样有block的概念,但是大的多,默认为64M。与单一磁盘上的文件系统类似,HDFS上的文件也被划分为块大小的多个分块(chunk),作为独立的存储单元。但与其他文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间。

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

但是这个数也不会设置得过大。MapReduce中的map任务通常一次只处理一个块中的数据,因此如果任务数太少(少于集群中的节点数量),作业的运行速度就会比较慢。

对分布式文件系统中的块进行抽象会带来很多好处。第一个是,一个文件的大小可以大于网络中任意一个磁盘的容量。第二个好处是,使用抽象块而非整个文件作为存储单元,简化了存储子系统的设计。不仅如此,块还非常适合用于数据备份进而提供数据容错能力和提高可用性。

1.2.2 namenode和datanode

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

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

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

对namenode实现容错非常重要,Hadoop为此提供两种机制。

第一种机制是备份那些组成文件系统的元数据持久状态的文件。另一种方法是运行一个辅助namenode,但它不能被用作namenode。

1.2.3 联邦HDFS

namenode在内存中保存文件系统中每个文件和每个数据块的引用关系,这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。

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

要想访问联邦HDFS集群,客户端需要使用客户端挂载数据表将文件路径映射到namenode。

1.2.4 HDFS的高可用性

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

1.namenode之间需要通过高可用的共享存储实现编辑日志的共享。当备用namenode接管工作之后,它将通读共享编辑日志至末尾,以实现与活动namenode的状态同步,并继续读取由活动namenode写入的新条目。

2.datanode需要同时向两个namenode发送数据块处理报告,因为数据块映射信息存储在namenode的内存中,而非磁盘。

3.客户端需要使用特定的机制来处理namenode的失效问题,这一机制对用户是透明的。

故障切换与规避

一个称为故障转移控制器的系统中有一个新实体管理着将活动namenode转移为备用namenode的转换过程。故障转移控制器是可插拔的,但其最初的实现是基于ZooKeeper的并由此确保有且仅有一个活动namenode。每一个namenode运行着一个轻量级的故障转移控制器,其工作是监视宿主namenode是否失效(通过一个简单的心跳机制)并在namenode失效时进行故障切换。

管理员也可以手动发起故障转移,这称为“平稳的故障转移”,因为故障转移控制器可以组织两个namenode有序切换角色。

但在非平稳故障转移的情况下,无法确切知道失效namenode是否已经停止运行。高可用实现做了进一步优化,以确保先前活动的namenode不会执行危害系统并导致系统崩溃的操作——规避。


1.3 Java接口

FileSystem类是与Hadoop的某一文件系统进行交互的API。

1.3.1 从Hadoop URL读取数据

最简单的方法是使用java.net.URL对象打开数据流,从中读取数据。如下:

InputStream in = null;try {in = new URL("hdfs://host/path").openStream();}finally{IOUtils.closeStream(in);}

让Java程序识别Hadoop的hdfs URL还需要一些额外的工作。这里是通过FsUrlStreamHandlerFactory实例调用java.url.URL对象的setURLStreamHandlerFactory方法。

1.3.2 通过FileSystem API读取数据

有时候,不可能在应用中设置URLStreamHandlerFactory实例。在这种情况下,需要使用FileSystem API来打开一个文件的熟人流。

Hadoop文件系统中通过Hadoop Path对象(非java.io.File对象,因为它的语义与本地文件系统联系太紧密)来代表文件。可以将路径视为一个Hadoop文件系统的URI。

1.3.3 写入数据

FileSystem类有一系列新建文件的方法。最简单的是给准备建的文件指定一个Path对象,然后返回一个用于写入数据的输出流:

public FSDataOutputStream create(Path f) throws IOException

此方法有多个重载版本,允许我们指定是否需要强制覆盖现有文件、文件备份数量、写入文件时所用的缓冲区大小、文件块大小以及文件权限。

create()方法能够为需要写入且当前不存在的文件创建父目录。尽管这样很方便,但有时并不希望这样。如果希望父目录不存在就导致文件写入失败,则应该先调用exists()方法检查父目录是否存在。

另一种新建文件的方法是使用append()方法在一个已有文件末尾追加数据(有重载版本):

public FSDataOutputStream append(Path f)throws IOException

这样的追加操作允许一个writer打开文件后在访问该文件的最后偏移量处追加数据。有了这个API,某些应用可以创建无边界文件。

1.3.4 目录

Filesystem实例提供了创建目录的方法:

public boolean mkdirs(Path f)throws IOException

这个方法可以一次性新建所有必要但还没有的父目录。如果目录都已经创建成功,则返回true。通常不需要显式创建一个目录,因为create()方法写入文件时会自动创建父目录。

1.3.5 查询文件系统

1.文件元数据:FileStatus

任何文件系统的一个重要特征都是提供其目录结构浏览和检索它所存文件和目录的相关信息的功能。FIleStatus类封装了文件系统中文件和目录的元数据,包括文件长度,块大小、复本、修改时间、所有者以及权限信息。

FileSystem的getFileStatus()方法用于获取文件或目录的FileStatus对象。

2.列出文件

查找一个文件或目录相关的信息很实用,但通常还需要能够列出目录中的内容。这就是FileSystem的listStatus()。

3.文件模式

在单个操作中处理一批文件试一个很常见的需求。在一个表达式中使用通配符来匹配多个文件是比较方便的,无需列举每个文件和目录来指定输入,该操作称为“通配”。Hadoop为执行通配提供了两个FileSystem方法。globStatus()方法返回与其路径匹配于指定模式的所有文件的FileStatus对象数组,并按路径排序。PathFilter命令作为可选项可以进一步对匹配结果进行限制。

4.PathFilter对象

通配符并不总能够精确地描述我们想要访问的文件集。FileSystem中的listStatus()和globStatus()方法提供了可选的PathFIlter对象,以编程方式控制通配符。

1.3.6 删除数据

使用FileSystem的delete()方法可以永久性地删除数据。


1.4 数据流

1.4.1 文件读取


1.4.2 文件写入


1.4.3 一致模型

文件系统的一致模型描述了文件读写的数据可见性。


原创粉丝点击