赞
踩
注:《Hadoop权威指南》重点学习摘要笔记
当数据集的大小超过一台独立的物理计算机的存储能力时,就有必要对它进行分区(partition)并存储到若干台单独的计算机上。管理网络中跨多台计算机存储的文件系统称为分布式文件系统(distributed filesystem)。该系统架构于网络之上,势必会引人网络编程的复杂性,因此分布式文件系统比普通磁盘文件系统更为复杂。例如,使文件系统能够容忍节点故障且不丢失任何数据,就是一个极大的挑战。
Hadoop自带一个称为HDFS的分布式文件系统,即Hadoop Distributed Filesystem。在非正式文档或旧文档以及配置文件中,有时也简称为DFS,它们是一回事儿。HDFS是Hadoop的旗舰级文件系统,也是本章的重点,但实际上Hadoop是一个综合性的文件系统抽象,因此接下来我们将了解将Hadoop与其他存储系统集成的途径,例如本地文件系统和AmazonS3系统。
HDFS以流式数据访问模式来存储超大文件,运行于商用硬件集群上。让我们仔细看看下面的描述:
同样,那些不适合在HDFS上运行的应用也值得研究。目前HDFS对某些应用领域并不适合,不过以后可能会有所改进。
每个磁盘都有默认的数据块大小,这是磁盘进行数据读/写的最小单位。构建于单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的块,该文件系统块的大小可以是磁盘块的整数倍。文件系统块一般为几千字节,而磁盘块一般为512字节。这些信息(文件系统块大小)对于需要读/写文件的文件系统用户来说是透明的。尽管如此,系统仍然提供了一些工具(如df和fsck)来维护文件系统,由它们对文件系统中的块进行操作。
HDFS同样也有块(block)的概念,但是大得多,默认为128MB。与单一磁盘上的文件系统相似,HDFS上的文件也被划分为块大小的多个分块(chunk),作为独立的存储单元。但与面向单一磁盘的文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间(例如,当一个1MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB)。如果没有特殊指出,本书中提到的“块”特指HDFS中的块。
HDFS中的块为什么那么大?
对分布式文件系统中的块进行抽象会带来很多好处。第一个最明显的好处是,一个文件的大小可以大于网络中任意一个磁盘的容量。文件的所有块并不需要存储在同一个磁盘上,因此它们可以利用集群上的任意一个磁盘进行存储。事实上,尽管不常见,但对于整个HDFS集群而言,也可以仅存储一个文件,该文件的块占满集群中所有的磁盘。
第二个好处是,使用抽象块而非整个文件作为存储单元,大大简化了存储子系统的设计。简化是所有系统的目标,但是这对于故障种类繁多的分布式系统来说尤为重要。将存储子系统的处理对象设置为块,可简化存储管理(由于块的大小是固定的,因此计算单个磁盘能存储多少个块就相对容易)。同时也消除了对元数据的顾虑(块只是要存储的大块数据,而文件的元数据,如权限信息,并不需要与块一同存储,这样一来,其他系统就可以单独管理这些元数据)。
不仅如此,块还非常适合用于数据备份进而提供数据容错能力和提高可用性。将每个块复制到少数几个物理上相互独立的机器上(默认为3个),可以确保在块、磁盘或机器发生故障后数据不会丢失。如果发现一个块不可用,系统会从其他地方读取另一个复本,而这个过程对用户是透明的。一个因损坏或机器故障而丢失的块可以从其他候选地点复制到另一台可以正常运行的机器上,以保证复本的数量回到正常水平。同样,有些应用程序可能选择为一些常用的文件块设置更高的复本数量进而分散集群中的读取负载。
与磁盘文件系统相似,HDFS中fsck指令可以显示块信息。例如,执行以下命令将列出文件系统中各个文件由哪些块构成。
通过联合使用在多个文件系统中备份namenode的元数据和通过备用namenode创建监测点能防止数据丢失,但是依旧无法实现文件系统的高可用性。namenode依旧存在单点失效(SPOF,single point of failure)的问题。如果namenode失效了,那么所有的客户端,包括MapReduce作业,均无法读、写或列举(list)文件,因为namenode是唯一存储元数据与文件到数据块映射的地方。在这一情况下,Hadoop系统无法提供服务直到有新的namenode上线。
在这样的情况下,要想从一个失效的namenode恢复,系统管理员得启动一个拥有文件系统元数据副本的新的namenode,并配置datanode和客户端以便使用这个新的namenode。新的namenode直到满足以下情形才能响应服务:
对于一个大型并拥有大量文件和数据块的集群,namenode的冷启动需要30分钟,甚至更长时间。
系统恢复时间太长,也会影响到日常维护。事实上,预期外的namenode失效出现概率很低,所以在现实中,计划内的系统失效时间实际更为重要。
Hadoop2针对上述问题增加了对HDFS高可用性(HA)的支持。在这一实现中,配置了一对活动-备用(active-standby)namenode。当活动namenode失效,备用namenode就会接管它的任务并开始服务于来自客户端的请求,不会有任何明显中断。实现这一目标需要在架构上做如下修改。
可以从两种高可用性共享存储做出选择:NFS过滤器或群体日志管理器(QJM,quorum journal manager)。QJM是一个专用的HDFS实现,为提供一个高可用的编辑日志而设计,被推荐用于大多数HDFS部署中。QJM以一组日志节点(journalnode)的形式运行,每一次编辑必须写入多数日志节点。典型的,有三个journal节点,所以系统能够忍受其中任何一个的丢失。这种安排与Zookeeper的工作方式类似,当然必须认识到,QJM的实现并没使用Zookeeper。(然而,值得注意的是,HDFS HA在选取活动的namenode时确实使用了Zookeeper技术)
在活动namenode失效之后,备用namenode能够快速(几十秒的时间)实现任务接管,因为最新的状态存储在内存中:包括最新的编辑日志条目和最新的数据块映射信息。实际观察到的失效时间略长一点(需要1分钟左右),这是因为系统需要保守确定活动namenode是否真的失效了。
在活动namenode失效且备用namenode也失效的情况下,当然这类情况发生的概率非常低,管理员依旧可以声明一个备用namenode并实现冷启动。这类情况并不会比非高可用(non·HA)的情况更差,并且从操作的角度讲这是一个进步,因为上述处理已是一个标准的处理过程并植人Hadoop中。
至此,文件系统已经可以使用了,我们可以执行所有常用的文件系统操作,例如,读取文件,新建目录,移动文件,删除数据,列出目录,等等。可以输人hadoop fs -help命令获取每个命令的详细帮助文件。
首先从本地文件系统将一个文件复制到HDFS:
%hadoop fs -copyFromLocal input/docs/quangle.txt \ hdfs://localhost/user/tom/quangle.txt
该命令调用Hadoop文件系统的shell命令fs,后者提供了一系列子命令,在这个例子中,我们执行的是-copyFromLocal。本地文件quangle.txt被复制到运行在localhost上的HDFS实例中,路径为/user/tom/quangle.txt。事实上,我们可以简化命令格式以省略主机的URI并使用默认设置,即省略hdfs://localhost,因为该项已在core-site.xml中指定。
%hadoop fs -copyFromLoca1 input/docs/quangle.txt /user/tom/quangle.txt
我们也可以使用相对路径,并将文件复制到HDFS的home目录中,本例中为
%hadoop fs -copyFromLoca1 input/docs/quangle.txt quangle.txt
我们把文件复制回本地文件系统,并检查是否一致:
%hadoop fs -copyToLocal quangle.txt quangle.copy.txt
%md5 input/docs/quangle.txt quangle.copy.txt
MD5(input/docs/quangle.txt)=e7891a2627cf263a979fb9f18256ffb2
MD5(quangle.copy.txt)=e7891a2627cf263a979fb9f18256ffb2
MD5键值相同,表明这个文件在HDFS之旅中得以幸存并保存完整。
最后,看一下HDFS文件列表。我们新建一个目录,看它在列表中怎么显示:
%hadoop fs -mkdir books
%hadoop fs -ls .
8. 返回的结果信息与Unix命令Is -l 的输出结果非常相似,仅有细微差别。第1列显示的是文件模式。第2列是这个文件的备份数(这在传统Unix文件系统是没有的)。由于我们在整个文件系统范围内设置的默认复本数为1,所以这里显示的也都是1。这一列的开头目录为空,因为本例中没有使用复本的概念,目录作为元数据保存在namenode中,而非datanode中。第3列和第4列显示文件的所属用户和组别。第5列是文件的大小,以字节为单位,目录为0。第6列和第7列是文件的最后修改日期与时间。最后,第8列是文件或目录的名称。
Hadoop有一个抽象的文件系统概念,HDFS只是其中的一个实现。Java抽象类org.apache.hadoop.fs.FileSystem定义了Hadoop中一个文件系统的客户端接口,并且该抽象类有几个具体实现,其中和Hadoop紧密相关的见表3.1。
Hadoop对文件系统提供了许多接口,它一般使用URI方案来选取合适的文件系统实例进行交互。举例来说,我们在前一小节中遇到的文件系统命令行解释器可以操作所有的Hadoop文件系统命令。要想列出本地文件系统根目录下的文件,可以输人以下命令:
%hadoop fs -ls file:///
尽管运行的MapReduce程序可以访问任何文件系统(有时也很方便),但在处理大数据集时,建议你还是选择一个有数据本地优化的分布式文件系统,如HDFS。
Hadoop是用Java写的,通过Java API可以调用大部分Hadoop文件系统的交互操作。例如,文件系统的命令解释器就是一个Java应用,它使用Java的FileSystem类来提供文件系统操作。其他一些文件系统接口也将在本小节中做简单介绍。这些接口通常与HDFS一同使用,因为Hadoop中的其他文件系统一般都有访问基本文件系统的工具(对于FTP,有FTP客户端;对于S3,有S3工具,等等),但它们大多数都能用于任何Hadoop文件系统。
有时间补上。
文件系统的一致模型(coherency model)描述了文件读/写的数据可见性。HDFS为性能牺牲了一些POSIX要求,因此一些操作与你期望的可能不同。
新建一个文件之后,它能在文件系统的命名空间中立即可见,如下所示:
但是,写人文件的内容并不保证能立即可见,即使数据流已经刷新并存储。所以文件长度显示为0:
当写人的数据超过一个块后,第一个数据块对新的reader就是可见的。之后的块也不例外。总之,当前正在写人的块对其他reader不可见。
HDFS提供了一种强行将所有缓存刷新到datanode中的手段,即对FSDataOutputStream调用hflush()方法。当hflush()方法返回成功后,对所有新的reader而言,HDFS能保证文件中到目前为止写人的数据均到达所有datanode的写人管道并且对所有新的reader均可见:
注意,hflush()不保证datanode已经将数据写到磁盘上,仅确保数据在datanode的内存中(因此,如果数据中心断电,数据会丢失)。为确保数据写人到磁盘上,可以用hsync()替代.
hsync()操作类似于POSIX中的fsync()系统调用,该调用提交的是一个文件描述符的缓冲数据。例如,利用标准Java API数据写人本地文件,我们能够在刷新数据流且同步之后看到文件内容:
在HDFS中关闭文件其实隐含了执行hflush()方法
待续…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。