第三章Hadoop 分布式系统(翻译粗略 优化中)

第三章 Hadoop 分布式系统

当数据库的量大到一个机器存储不了的时候,那么把这些数据分隔开放到很多机器上面就是必要的了。管理网络上的机器的数据的文件系统,叫做分布式文件系统。因为是基于网络的,那么网络的一些问题就会被带到这里面来了,这使得分布式文件系统比通常的文件系统复杂多了。例如,最大的挑战就是,当节点存储数据失败时,整个数据不能丢失。

Hadoop分布式文件系统叫做HDFS,。。。事实上hadoop有一个通用文件系统的抽象,因此,今后,我们会了解到hadoop是怎样和其它存储系统整合的(例如本机系统和Amazon S3)。

HDFS的设计

HDFS是被设计用来存储超大文件,用流数据访问,运行在商务硬件集群上面的文件系统。

目前HDFS的缺点:

高延迟,许多小的文件,不能多用户修改,随时修改。

HDFS概念

一个硬盘有一个块的大小,这个大小是数据可以被读写的最小值。在用这样的块,来处理数据的一个单独硬盘,这上面的文件系统,就是由这些小块组成的。 文件系统一般是好几G,而,硬盘的小块是一般是512字节。对于只是读写文件的用户来说,无论这个块多大,这些都是透明的。然而,有一些工具是来维护文件系统的,例如dffsck,他们操作文件系统的块级别的数据。

HDFS也是如此,有块的概念,但是他的块是更大的单---默认64M。就像一个单独硬盘里面的文件系统,HDFS中的文件被分割成这种块大小的许多块,文件被作为一个独立的单元存储起来。不像一个单独硬盘里面的文件系统,HDFS中的文件要比块小得多,他不占用整个块的全部空间。本书中,如果不特殊说明,块指的就是HDFS中的块。

块如此大的原因:minimize the cost of seeks

对于分布式文件系统来说,把块的概念抽象化是有很多好处的。第一个好处也是最明显的就是:一个文件可以比网络中的一个单独硬盘都大。文件中的所有的块都存储在同一个硬盘上面是没有必要的,这样的话,他们可以充分利用集群中的任何磁盘。事实上,在特殊情况下,下面的事情是可能的,HDFS集群中的一个单独的文件把集群中所有的硬盘都给填满了。(即这个文件超级大)

第二个好处是:以一个抽象的块作为存储单元而不是一个文件,这样简化了存储系统。存储系统处理块,简化了存储管理,(因为块的大小是固定的,那么对于一个给定的硬盘,可以存储多少东西是可以计算的)消除了对元数据的关注(块存储的仅仅是数据,文件的元数据,像,权限信息,是不被存储在块中的,因此,另一个系统可以单独的处理元数据)。

另一个好处是:块在处理复制文件时候的容错率和可用性是很好的。为了应对块的损坏或硬盘或整个机器的损坏,每个块都被复制好几份存储在物理上分开的机器上面(一般是三份)。

就像文件系统的堂兄一样,HDFSfsck命令能够处理块。例如:% hadoop fsck / -files blocks

这个命令会列出在文件系统中,组成这个文件的所有块。

Name节点和data节点

Name节点管理文件系统树和所有文件的元数据,和树中的所有目录。这些信息被永久的存储在本机上面,信息的存储是以两个文件的形式:命名空间镜像和编辑的日志。Name节点同样知道,对于一个给定的文件,他的所有的块都存储在哪些节点上面,但是它不会永久的存储这些东西,因为当系统重启的时候,这些信息都会被重构。

一个客户端,为用户提供文件系统的访问,这种访问是和name节点和data节点交互。客户端提供文件系统的接口,因此用户的代码不需要详细了解name节点和data节点就可以操作了。

没有name节点,文件系统无法工作,hadoop有两种机制来阻止name节点挂掉。

第一种方法是备份,组成了文件系统元数据的持久状态,的文件。Hadoop可以配置name节点把它的持久状态写到多个文件系统。这些写入都是异步的和自动的。通常的配置是写到本地磁盘和远端的网络文件系统上面。

第二种方法是备份name节点。

然而,第二个name节点是落后于原始name节点的,所以,一旦原始节点完全挂掉的话,数据的丢失几乎是确定的事情。通常的处理步骤是,从NFS上拷贝name节点的元数据到第二个name节点上面,并把它当做新的原始name节点。

Hadoop命令行

复制等命令。。。。

Hadoop 文件系统

Hadoop有一个文件系统的抽象概念,HDFS只是其中的一个实现。Java org.apache.hadoop.fs.FileSystem,代表hadoop中的一个文件系统。除此之外还有其它的几个具体实现,下表中描述了:

接口

Hadoopjava语言写的,所有的hadoop文件系统的交互是由java api 调解的。例如,文件系统的shell命令,是一个使用javaFileSystem 类提供文件操作的java程序。在这部分中,其它文件系统的接口只做简单讨论。这些接口,通常情况下是HDFS使用的,因为hadoop中的其他文件系统都有自己典型的工具,来访问基础的文件系统。(FTPFTP客户端,S3S3工具等等),但是这些接口中的大多数都能够处理任何一种Hadoop文件系统。

Thrift

通过一个java api 暴露文件系统的接口,hadoop使非java程序访问hadoop文件系统变得很尴尬。发行版中的Thrift AP很好的解决了这个缺点,它把hadoop文件系统作为了一个Apache Thrift 服务,使得任何有Thrift绑定的语言都轻而易举的与hadoop文件系统交流,例如HDFS

要使用Thrift API,就要运行一个java服务器,这个java服务器暴露了Thrift 服务并且扮演了hadoop文件系统的代理。你的程序访问Thrift 服务,这个服务通常和你的程序运行在同一个机器上面。

Thrift API有很多之前生成的很多语言写的代码块,包括C++PerlPHPPython,和RubyThrift支持版本控制,因此,如果你想用同样的客户端代码访问不同版本的Hadoop文件系统,Thrift是一个很好的选择。(你需要运行每个Hadoop版本的代理)

关于Thrift的安装和使用说明,请参考如下文档src/contrib/thriftfs

C

Hadoop提供一个C库叫做libhdfs,它映射了java FileSystem接口(他被写出来是用来访问HDFS的,但是不管他的名字的话,他可以被用来访问任何的hadoop文件系统)。他用JNI来调用java文件系统客户端。C语言的APIjava相似,但是他是落后于java的。因此,一些新的特性C API可能还不支持。你可以找到为C语言API生成的文档,地址libhdfs/docs/api 

Hadoop预先为32位的linux系统编译了libhdfs二进制文件,但是对于其他平台,你需要自己编译,参考文档http://wiki.apache.org/hadoop/LibHDFS.

用户空间文件系统

用户空间文件系统,允许用户空间实现的文件系统整合成Unix文件系统。。。。

WebDAV

WebDAVHTTP的一系列扩展,它支持编辑和更新文件。WebDAV可以作为文件系统安装在大多数的操作系统上面,所以通过把HDFS暴露在WebDAV上面,可以把HDFS当做一个标准的文件系统来访问。

在本书写的时候,HadoopWebDAV的支持仍在开发中(靠调用hadoopjava api 来实现的)可以在如下的网站查看进度,https://issues.apache.org/jira/browse/HADOOP-496

其它的HDFS接口

有两个只针对HDFS的接口:

HTTP

HDFS定义了一个通过HTTP,能够检索目录列表和数据的只读接口。目录列表是由name节点的嵌入式网络服务器(运行在50070端口上面)提供的XML格式的,文件数据是通过服务器从数据节点传输过来的,(运行在50075端口上面)这个协议没有绑定到特定的HDFS版本,所以,客户端可以用HTTP读执行不同版本HadoopHDFSHftpFileSystem是这样的一个客户端:他是一个Hadoop文件系统,通过HTTPHDFS交流。

FTP

尽管本书写的时候,还没有完成,((https://issues.apache.org/jira/browse/HADOOP-3199)在HDFS中有一个FTP接口,允许使用FTP协议来和HDFS交流。这个接口是与HDFS进行数据传输,非常方便的方法,使用现有的FTP客户端即可。

HDFSFTP接口与FTPFileSystem是不混淆的,前者把任何FTP服务作为Hadoop文件系统暴露。

Java 接口

在文章的这部分,我们讨论hadoopFileSystem类,和Hadoop的文件系统交流的API

。。。。。。。

Page62

数据流

读一个文件的分解

要了解数据在客户端和HDFS上,name节点,data节点上是怎样传输的,请看下图:

写一个文件的分解

相关模型

文件系统的相关模型描述了一个文件的读写数据的可见性。HDFS为了性能的需求,抛弃了一些POSIX需求,一些操作的结果可能与你预期的不一样。

在创建完一个文件以后,文件系统命名空间中应该能够看到他,预期效果是如下这样的:

Path p = new Path("p");

fs.create(p);

assertThat(fs.exists(p), is(true));

但是,任何往这个文件里面写的内容,都是不保证能够看到的,甚至是流被刷新了。文件的长度查询出来可能是0。

Path p = new Path("p");

OutputStream out = fs.create(p);

out.write("content".getBytes("UTF-8"));

out.flush();

assertThat(fs.getFileStatus(p).getLen(), is(0L));

一旦,多于一个块的数据被写进去,那么,第一个块的数据对于新的读用户来说是可见的。对于后来的块,同样如此:当前被写的块,对于其他用户来说是不可见的。

HDFS提供了一个方法,这个方法强制所有的缓冲区与data节点同步,此方法使用的是FSDataOutputStream的synv()方法。在sync()方法成功返回值后,HDFS能够保证截止到那刻被写入的数据,被持久化起来了,并且对所有的读用户都是可见的。

Path p = new Path("p");

FSDataOutputStream out = fs.create(p);

out.write("content".getBytes("UTF-8"));

out.flush();

out.sync();

assertThat(fs.getFileStatus(p).getLen(), is(((long) "content".length())));

对程序设计的影响

这种相关模型对程序设计是有影响的。不调用sync()方法的话,那么,如果客户端或者系统崩溃的话,你要做好丢失一块数据的准备了。对于大多数程序来说,这都是不能接受的,因此,在你写完一些记录和一些字节之后,你应该在合适的地方调用sync()方法。

distcp平行的拷贝数据

到目前为止,我们所看到的HDFS访问模式都是单线程的访问。指明文件组之后,我们可以用单线程模式来处理一些文件集合,但是,为了高效率,你不得不自己写个程序来用多线程处理文件。Hadoop有一个有用的程序叫做distcp,它能够是用多线程拷贝Hadoop文件系统的数据。

Distcp的标准应用,是在两个HDFS集群之间传递数据。如果这两个集群上Hadoop的版本不一样,那么,hdfs框架也是适合的:

% hadoop distcp hdfs://namenode1/foo hdfs://namenode2/bar

默认情况下,dustcp会会跳过目的地已经存在的文件,但是这些已经存在的文件可以被覆盖,你可以使用-overwrite选项。你也可以使用-updata选项来更新变化的文件。

Distcp 被应用于如下的mapreduce作业,这些作业maps处理集群之间的数据传输。每一个文件都被一个单独的map函数拷贝,distcp尽力去给每个map分配相近的数据量。

如果你要在两个不同版本的HDFS集群上面,使用distcp,这时候你使用hdfs协议,拷贝就会失败,因为RPC是不兼容的。为了修复这个问题,你可以使用只读的基于HTTP的HFTP文件系统。这个工作一定要运行在目标集群上面,这样的话,HDFS RPC版本控制才是兼容的。下面用HFTP来重复上面的例子:

% hadoop distcp hftp://namenode1:50070/foo hdfs://namenode2/bar

注意,这里,你需要指明源URI在name节点的端口号。这是由dfs.http.address的属性决定的,默认端口号是50070。

Hadoop归档

HDFS存储小的文件效率低,因为每个文件都存储在一个块上面,并且,块的元数据是存储在name节点的内存中的。因此,大量的小文件会吃掉name节点上面的大量内存。(注意:无论如何,小文件都不会占用他所需要的多余空间,例如,1M文件存储在128M的块上面,它占用的是1M,而不是128M。)

Hadoop归档文件,或者说是HAR文件,是一个文档机制,他使文件打包进HDFS块更高效,减少name节点的内存使用,并且此时,对文件的访问仍是透明的。事实上,Hadoop归档可以被用来作为mapreduce的输入。

使用Hadoop归档

一个Hadoop归档是用archive工具收集文件来创建的。这个工具运行mapreduce作业来多线程处理输入的文件,所以为了使用这个工具,你需要一个mapreduce集群。下面是一些HDFS中我们想要归档的文件:

% hadoop fs -lsr /my/files

-rw-r--r-- 1 tom supergroup 1 2009-04-09 19:13 /my/files/a

drwxr-xr-x - tom supergroup 0 2009-04-09 19:13 /my/files/dir

-rw-r--r-- 1 tom supergroup 1 2009-04-09 19:13 /my/files/dir/b

现在,我们可以运行archive命令了:

hadoop archive -archiveName files.har /my/files /my

第一个参数是归档的名字,这里是files.har。HAR文件总是以.har作为扩展名,这是强制的,这个原因稍后解释。下一步就是把文件,放进归档里面去。这里我们只归档了一个文件树,是HDFS中的/my/files下的所有文件,但是这个工具是可以操作多个目录下面的文件树的。最后的那个参数是HAR文件的输出目录。让我们看看归档都创建了什么:

% hadoop fs -ls /my

Found 2 items

drwxr-xr-x - tom supergroup 0 2009-04-09 19:13 /my/files

drwxr-xr-x - tom supergroup 0 2009-04-09 19:13 /my/files.har

% hadoop fs -ls /my/files.har

Found 3 items

-rw-r--r-- 10 tom supergroup 165 2009-04-09 19:13 /my/files.har/_index

-rw-r--r-- 10 tom supergroup 23 2009-04-09 19:13 /my/files.har/_masterindex

-rw-r--r-- 1 tom supergroup 2 2009-04-09 19:13 /my/files.har/part-0

目录列出了一个HAR文件的组成:两个索引文件和一个碎片文件的集合(本例中只有一个小文件的集合)。这个碎片文件包括原来的小文件的集合,并且,索引使得归档文件中的碎片文件的位置、大小查询,是可能的。所有的这些细节对应用程序是隐藏的,但是,程序是用har URI来与HAR文件交流的。

下面的命令递归的列出了归档中的文件:

% hadoop fs -lsr har:///my/files.har

drw-r--r-- - tom supergroup 0 2009-04-09 19:13 /my/files.har/my

drw-r--r-- - tom supergroup 0 2009-04-09 19:13 /my/files.har/my/files

-rw-r--r-- 10 tom supergroup 1 2009-04-09 19:13 /my/files.har/my/files/a

drw-r--r-- - tom supergroup 0 2009-04-09 19:13 /my/files.har/my/files/dir

-rw-r--r-- 10 tom supergroup 1 2009-04-09 19:13 /my/files.har/my/files/dir/b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值