介绍
视图文件系统( ViewFs )提供了一种管理多个 Hadoop 文件系统名称空间(或名称空间卷)的方法。对于具有多个 namenode 的集群,因此在 HDFS 联合中具有多个名称空间,这一点特别有用。ViewFs 类似于某些 Unix/Linux 系统中的客户端挂载表。ViewFs 可以用来创建个性化的名称空间视图,也可以创建每个集群的通用视图。
本指南是在具有多个集群的 Hadoop 系统上下文中提供的,每个集群可以联合到多个名称空间中。它还描述了如何在联邦 HDFS 中使用 ViewFs 来提供每个集群的全局名称空间,以便应用程序能够以类似于联邦前的方式进行操作。
HDFS 联邦之前
Single Namenode Clusters
在 HDFS 联邦之前的旧世界中,集群有一个 namenode,它为集群提供一个文件系统名称空间。假设有多个集群。每个集群的文件系统名称空间是完全独立的。此外,物理存储不能跨集群共享(即 DataNode 不能跨集群共享)。
每个集群的 core-site.xml 都有一个配置属性,它将默认文件系统设置为该集群的 namenode:
<property>
<name>fs.default.name</name>
<value>hdfs://namenodeOfClusterX:port</value>
</property>
这样的配置属性允许使用斜杠相对名称来解析相对于集群 namenode 的路径。例如,path /foo/bar 引用了上面配置的 hdfs://namenodeOfClusterX:port/foo/bar。
这个配置属性在集群上的每个网关以及该集群的关键服务(如 JobTracker 和 Oozie )上设置。
路径名的使用
因此,在如上设置 core-site.xml 的集群X上,典型的路径名是
-
/foo/bar
- 这相当于以前的 hdfs://namenodeOfClusterX:port/foo/bar。
-
hdfs://namenodeOfClusterX:port/foo/bar
- 虽然这是一个有效的路径名,但最好使用/foo/bar,因为它允许应用程序及其数据在需要时透明地移动到另一个集群。
-
hdfs://namenodeOfClusterY:port/foo/bar
- 它是一个 URI,用于引用另一个集群(比如集群Y)上的路径名。
distcp hdfs://namenodeClusterY:port/pathSrc hdfs://namenodeClusterZ:port/pathDest
- 它是一个 URI,用于引用另一个集群(比如集群Y)上的路径名。
-
webhdfs://namenodeClusterX:http_port/foo/bar
- 它是一个 URI,用于通过WebHDFS文件系统访问文件。注意,WebHDFS 使用 namenode 的 HTTP 端口,而不是 RPC 端口。
-
http://namenodeClusterX:http_port/webhdfs/v1/foo/bar and http://proxyClusterX:http_port/foo/bar
- 这是分别用于通过 WebHDFS REST API 和 HDFS 代理访问文件的 HTTP url。
路径名使用最佳实践
在集群中,建议使用上面类型(1)的路径名,而不是像(2)这样的完全限定URI。
HDFS 联邦和 ViewFs
集群的外观
假设有多个集群。每个集群都有一个或多个 namenode。每个 namenode 都有自己的名称空间。一个 namenode 只属于一个集群。同一集群中的 namenode 共享该集群的物理存储。集群之间的名称空间与以前一样是独立的。
操作根据存储需要决定集群中的每个 namenode 上存储什么。例如,他们可能把所有的用户数据(/user/<username>)放在一个 namenode 中,把所有的 feed 数据(/data)放在另一个 namenode 中,把所有的项目(/projects)放在另一个 namenode 中,等等。
使用ViewFs为每个集群提供全局命名空间
为了提供之前集群的透明性,ViewFs 文件系统(即客户端挂载表)用于为每个集群创建一个独立的集群名称空间视图,它类似于以前的 namespace。客户端挂载表与 Unix 挂载表类似,它们使用旧的命名约定挂载新的名称空间卷。下图显示了一个挂载表,挂载四个名称空间卷/user、/data、/projects和/tmp:
ViewFs实现了Hadoop文件系统接口,就像HDFS和本地文件系统一样。从只允许链接到其他文件系统的意义上说,它是一个普通的文件系统。因为ViewFs实现了Hadoop文件系统接口,所以它可以透明地工作于Hadoop工具中。例如,所有shell命令与ViewFs一起工作,就像与HDFS和本地文件系统一样。
在每个集群的配置中,默认文件系统设置为该集群的挂载 v 表,如下所示(将其与单个 Namenode 集群中的配置进行比较)。
<property>
<name>fs.defaultFS</name>
<value>viewfs://clusterX</value>
</property>
URI 中 viewfs:// 方案后面的权限是挂载表名。建议集群的挂载表按集群名命名。然后 Hadoop 系统将在 Hadoop 配置文件中查找名为 “clusterX” 的挂载表。操作安排所有网关和服务机器包含所有集群的挂载表,这样,对于每个集群,默认文件系统设置为上述集群的 ViewFs 挂载表。
挂载表的挂载点在标准 Hadoop 配置文件中指定。viewfs 的所有挂载表配置项都以 fs.viewfs.mounttable 为前缀。链接其他文件系统的挂载点是使用链接标记指定的。建议将挂载点的名称与链接的文件系统目标位置中的名称相同。对于没有在挂载表中配置的所有名称空间,我们可以通过 linkFallback 让它们回退到默认的文件系统。
在下面的挂载表配置中,命名空间 /data 链接到文件系统 hdfs://nn1-clusterx.example.com:8020/data, /project 链接到文件系统hdfs://nn2-clusterx.example.com:8020/project。所有没有在挂载表中配置的名称空间,比如 /log,都链接到文件系统hdfs://nn5-clusterx.example.com:8020/home。
<configuration>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./data</name>
<value>hdfs://nn1-clusterx.example.com:8020/data</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./project</name>
<value>hdfs://nn2-clusterx.example.com:8020/project</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./user</name>
<value>hdfs://nn3-clusterx.example.com:8020/user</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./tmp</name>
<value>hdfs://nn4-clusterx.example.com:8020/tmp</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.linkFallback</name>
<value>hdfs://nn5-clusterx.example.com:8020/home</value>
</property>
</configuration>
或者,我们可以通过 linkMergeSlash 将挂载表的根与另一个文件系统的根合并。在下面的挂载表配置中,ClusterY 的根被合并到hdfs://nn1-clustery.example.com:8020 上的根文件系统。
<configuration>
<property>
<name>fs.viewfs.mounttable.ClusterY.linkMergeSlash</name>
<value>hdfs://nn1-clustery.example.com:8020/</value>
</property>
</configuration>
路径名的使用模式
因此,在集群 X 上,将 core-site.xml 设置为使用该集群的挂载表的默认 fs,典型的路径名是
- /foo/bar
这相当于 viewfs://clusterX/foo/bar。如果在旧的非联邦中使用了这样的路径名,那么到联邦的转换是透明的。
- viewfs://clusterX/foo/bar
虽然这是一个有效的路径名,但最好使用/foo/bar,因为它允许应用程序及其数据在需要时透明地移动到另一个集群。
-
viewfs://clusterY/foo/bar
它是一个URI,用于引用另一个集群(比如集群Y)上的路径名。distcp viewfs://clusterY/pathSrc viewfs://clusterZ/pathDest
-
viewfs://clusterX-webhdfs/foo/bar
它是一个URI,用于通过WebHDFS文件系统访问文件。
-
http://namenodeClusterX:http_port/webhdfs/v1/foo/bar and http://proxyClusterX:http_port/foo/bar
这是分别用于通过 WebHDFS REST API 和 HDFS 代理访问文件的 HTTP url。注意,它们与之前的相同。
路径名使用最佳实践
当一个人在一个集群中,推荐使用式(1)以上的路径名,而不是一个完全合格的URI(2)。此外,应用程序不应该使用挂载点的知识和使用 hdfs 这样的路径:hdfs://namenodeContainingUserDirs:port/joe/foo/bar 引用一个文件在一个特定的namenode。应该使用 /user/joe/foo/bar 代替。
跨名称空间重命名路径名
以前不能重命名文件或者 namenode 中的目录,现在也不能。但是以前可以执行如下操作:
rename /user/joe/myStuff /data/foo/bar
如果 /user 和 /data 实际上存储在一个集群中的不同 namenode上,那么这种方法将无法工作。
具有Nfly挂载点的多文件系统I/0
HDFS 和其他分布式文件系统通过一些冗余(如块复制或更复杂的分布式编码)来提供数据弹性。然而,现代的设置可能包含多个Hadoop 集群、企业文件程序,它们在运行和关闭的前提下运行。Nfly 挂载点使得多个文件系统可以同步复制一个逻辑文件。它是为一个相对较小的文件设计的,最高可达 1gb。一般来说,它是单核心/单网络链接性能的函数,因为逻辑驻留在使用诸如FsShell 或 MapReduce 任务等 ViewFs 的单个客户端 JVM 中。
基本配置
考虑下面的示例来理解 Nfly 的基本配置。假设我们希望将目录 ads 复制到三个文件系统上,这三个文件系统由 uri 表示:uri1、uri2 和 uri3。
<property>
<name>fs.viewfs.mounttable.global.linkNfly../ads</name>
<value>uri1,uri2,uri3</value>
</property>
注2连续..在属性名称中。它们的出现是因为对挂载点进行高级调整的设置是空的,我们将在后面的部分中展示这一点。属性值是一个逗号分隔的uri列表。
uri 可能指向不同区域的不同集群:hdfs:// datactor -east/ads, s3a://models-us-west/ads, hdfs:// datactor -west/ads,或者在最简单的情况下指向同一文件系统下的不同目录,例如:file:/tmp/ads1, file:/tmp/ads2, file:/tmp/ads3
如果底层系统可用,在 global path viewfs://global/ads下执行的所有修改都会传播到所有目标 uri。
例如,如果我们通过 hadoop shell 创建一个文件
hadoop fs -touchz viewfs://global/ads/z1
在后面的配置中,我们将通过本地文件系统找到它
ls -al /tmp/ads*/z1
-rw-r--r-- 1 user wheel 0 Mar 11 12:17 /tmp/ads1/z1
-rw-r--r-- 1 user wheel 0 Mar 11 12:17 /tmp/ads2/z1
-rw-r--r-- 1 user wheel 0 Mar 11 12:17 /tmp/ads3/z1
从全局路径读取的数据由第一个文件系统处理,不会导致异常。文件系统被访问的顺序取决于它们此时是否可用,或者是否存在拓扑顺序。
先进配置
linkNfly 的挂载点可以使用参数进一步配置,这些参数通过逗号分隔的键=值对列表传递。目前支持以下参数。
minReplication=int 确定如果下面的 nfly 写操作失败,必须无异常地处理写修改的最小目的地数。将 minReplication 设置为高于目标 uri 数量是一种配置错误。默认值是2。
如果 minReplication 小于目标 uri 的数量,我们可能会有一些没有最新写操作的目标 uri。它可以通过使用由以下设置控制的更昂贵的读取操作来补偿
readMostRecent=boolean 如果设置为 true, Nfly 客户端会检查所有目标 uri 下的路径,而不是根据拓扑顺序只检查第一个。在目前所有可用的文件中,将处理修改时间最近的文件。
repairOnRead=boolean 如果设置为 true,则 Nfly 会将最近的副本复制到固定的目标,这样后续的读取就可以从最近的副本中廉价地完成。
拓扑结构
Nfly 寻求满足从“最近的”目标 URI 读取。
为此,Nfly 将机架感知的概念扩展到目标 uri 的权限。
Nfly 应用网络拓扑来解析 uri 的权限。最常见的是在异构设置中使用基于脚本的映射。我们可以使用提供以下拓扑映射的脚本
URI | Topology |
---|---|
hdfs://datacenter-east/ads | /us-east/onpremise-hdfs |
s3a://models-us-west/ads | /us-west/aws |
hdfs://datacenter-west/ads | /us-west/onpremise-hdfs |
如果目标 URI 没有 file:/ Nfly 中的权限部分,则注入客户端的本地节点名称。
nfly 配置示例
<property>
<name>fs.viewfs.mounttable.global.linkNfly.minReplication=3,readMostRecent=true,repairOnRead=false./ads</name>
<value>hdfs://datacenter-east/ads,hdfs://datacenter-west/ads,s3a://models-us-west/ads,file:/tmp/ads</value>
</property>
Nfly 文件如何创建工作
FileSystem fs = FileSystem.get("viewfs://global/", ...);
FSDataOutputStream out = fs.create("viewfs://global/ads/f1");
out.write(...);
out.close();
上面的代码将导致下面的执行。
-
在每个目标 URI 下创建一个不可见的文件 _nfly_tmp_f1。, hdfs://datacenter-east/ads/_nfly_tmp_f1, hdfs://datacenter-west/ads/_nfly_tmp_f1 等这是通过调用底层文件系统上的 create 来完成的,并返回一个封装了所有四个输出流的 FSDataOutputStream 对象。
-
因此,每个后续写入输出都可以转发到每个包装流。
-
上了。关闭所有流被关闭,文件被从 _nfly_tmp_f1 重命名为f1。在此步骤开始时,所有文件接收到的修改时间与客户端系统时间相同。
-
如果至少 minReplication 目的地已经完成步骤1-3而没有失败,Nfly 会考虑逻辑提交的事务;否则,它会尽力清理临时文件。
注意,因为 4 是最优的步骤,而且客户机 JVM 可能会崩溃并且永远不会恢复其工作,所以提供某种类型的 crontab 作业来清除这样的 _nfly_tmp 文件。
FAQ
-
从非联邦世界到联邦世界,我需要记录不同卷的 namenode;我怎么做呢?
不,你不会的。看看上面的例子-你要么使用一个相对的名字并利用默认的文件系统,要么改变你的路径从 hdfs://namenodeCLusterX/foo/bar 到 viewfs://clusterX/foo/bar。
-
在集群中,将一些文件从一个 namenode 移动到另一个 namenode 的操作会发生什么?
为了处理存储容量问题,操作可以将文件从一个 namenode 移动到另一个 namenode。它们这样做是为了避免应用程序崩溃。让我们举几个例子。
-
Example 1: /user and /data 在一个 namenode 上,之后它们需要在单独的 namenode 上处理容量问题。实际上,操作将为 /user 和 /data 创建单独的挂载点。在更改之前,/user 和 /data 的挂载应该指向相同的 namenode,比如namenodeContainingUserAndData。操作将更新挂载表,以便将挂载点分别更改为 namenodeContaingUser 和 namenodeContainingData。
-
Example 2: 所有项目都安装在一个 namenode 上,但后来它们需要两个或更多的 namenode。ViewFs 允许像 /project/foo 和 /project/bar 这样的挂载。这允许将挂载表更新为指向相应的 namenode。
-
-
挂载表是在每个 core-site.xml 中,还是在单独的文件中?
计划是将挂载表保存在单独的文件中,并让 core-site.xml x包含它。虽然可以将这些文件本地保存在每台机器上,但最好使用 HTTP 从中心位置访问它。
-
配置应该只有一个集群的挂载表定义还是所有集群的挂载表定义?
配置应该有所有集群的挂载定义,因为需要访问其他集群中的数据,比如 distcp。
-
如果操作可能随着时间的推移而改变挂载表,那么挂载表什么时候实际读取?
当作业提交给集群时,将读取挂载表。xml 中的 XInclude 在作业提交时展开。这意味着,如果挂载表被更改,则需要重新提交作业。由于这个原因,我们希望实现合并挂载,这将大大减少更改挂载表的需要。此外,我们希望通过另一种机制来读取挂载表,这种机制将来在作业开始时进行初始化。
-
JobTracker (或者 Yarn 的资源管理器)本身会使用 ViewFs 吗?
不,不需要。NodeManager 也不知道。
-
ViewFs 只允许挂载在顶层吗?
没有;它更普遍。例如,可以挂载 /user/joe 和 /user/jane。在这种情况下,在挂载表中为 /user 创建一个内部只读目录。除了 /user 是只读之外,/user 上的所有操作都是有效的。
-
应用程序可以跨集群工作,并且需要持久地存储文件路径。它应该存储哪些路径?
您应该存储 viewfs://cluster/path 类型的路径名,与运行应用程序时使用的路径名相同。只要操作以透明的方式进行移动,就可以将您与集群内 namenode 中的数据移动隔离开来。如果数据从一个集群移动到另一个集群,它不会隔离您;旧的世界(前联邦时代)无论如何也不能保护您跨集群进行这种数据移动。
-
那么委托令牌呢?
将作业提交到的集群(包括该集群挂载表的所有挂载卷)和 map-reduce 作业的输入和输出路径(包括通过挂载表挂载的指定输入和输出路径的所有卷)的委托令牌都将自动处理。此外,还有一种方法可以在特殊情况下向基本集群配置添加额外的委托令牌。
附录:一个挂载表配置示例
通常,用户不必定义挂载表或 core-site.xml 来使用挂载表。这是通过操作完成的,在正确的网关机器上设置正确的配置,就像现在的 core-site.xml 所做的那样。
可以在 core-site.xml 中描述挂载表,但是最好在 core-site.xml 中使用间接引用单独的配置文件,比如 mountTable.xml。在 core-site.xml 中添加以下配置元素,用于引用 mount .xml:
<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="mountTable.xml" />
</configuration>
在可挂载文件中。对于由三个 namenode 管理的三个名称空间卷联合的假设集群,有一个挂载表“ClusterX”的定义
- nn1-clusterx.example.com:8020,
- nn2-clusterx.example.com:8020, and
- nn3-clusterx.example.com:8020.
这里 /home 和 /tmp 位于 namenode nn1-clusterx.example.com:8020 管理的名称空间中,projects /foo 和 /bar 托管在联邦集群的其他名称空间中。主目录基路径设置为 /home,以便每个用户都可以使用在 FileSystem/FileContext 中定义的getHomeDirectory() 方法访问其主目录。
<configuration>
<property>
<name>fs.viewfs.mounttable.ClusterX.homedir</name>
<value>/home</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./home</name>
<value>hdfs://nn1-clusterx.example.com:8020/home</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./tmp</name>
<value>hdfs://nn1-clusterx.example.com:8020/tmp</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./projects/foo</name>
<value>hdfs://nn2-clusterx.example.com:8020/projects/foo</value>
</property>
<property>
<name>fs.viewfs.mounttable.ClusterX.link./projects/bar</name>
<value>hdfs://nn3-clusterx.example.com:8020/projects/bar</value>
</property>
</configuration>