03、Hadoop 教程 - Hadoop HDFS REST HTTP API

1. HDFS REST HTTP API

上一篇讲的 HDFS shell 客户端和 Java 客户端,都安装了HDFS客户端。在 windows 上也配置了 HDFS 的 windows 版本客户端,否则,我们将无法操作 HDFS。而且,客户端的版本如果不匹配,有可能会导致无法操作。
如果出现了譬如下面这种没有安装HDFS客户端的机器上操作该如何呢?
 
下面我们讲几种基于 HTTP 协议的客户端,HTTP 是跨平台的,它不要求客户端上必须安装 Hadoop,就可以直接操作 HDFS。

1.1 WebHDFS

 

1.1.1 简介

WebHDFS 其实是 HDFS 提供的 HTTP RESTFul API 接口,并且它是独立于 Hadoop 的版本的,它支持 HDFS 的完整 FileSystem / FileContext 接口。它可以让客户端发送 http 请求的方式来操作 HDFS,而无需安装 Hadoop。

1.1.2 关于RESTful

1.1.2.1 REST

 

  • REST(表现层状态转换,英语:Representational State Transfer)是 Roy Thomas Fielding 博士于 2000 年在博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。

  • REST 是基于超文本传输协议(HTTP)之上而确定的一组约束和属性,是一种设计提供万维网络服务的软件构建风格。符合或兼容于这种架构风格(简称为 REST 或 RESTful)的网络服务,允许客户端发出以统一资源标识符访问和操作网络资源的请求,而与预先定义好的无状态操作集一致化。

  • 因此 REST 提供了在互联网络的计算系统之间,彼此资源可交互使用的协作性质(interoperability)。相对于其它种类的网络服务,例如 SOAP 服务,则是以本身所定义的操作集,来访问网络上的资源。

  • 目前在三种主流的 Web 服务实现方案中,因为 REST 模式与复杂的 SOAP 和 XML-RPC 相比更加简洁,越来越多的 Web 服务开始采用 REST 风格设计和实现。例如,Amazon.com 提供接近 REST 风格的 Web 服务运行图书查询;雅虎提供的 Web 服务也是 REST 风格的。

  • 需要注意的是,REST 是设计风格而不是标准。REST 通常基于 HTTP、URI、XML 以及 HTML 这些现有的广泛流行的协议和标准。

  • 资源是由 URI 来指定。

  • 对资源的操作包括获取、创建、修改和删除,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。

  • 通过操作资源的表现形式来操作资源。

  • 资源的表现形式则是 XML 或者 HTML,取决于读者是机器还是人、是消费 Web 服务的客户软件还是 Web 浏览器。当然也可以是任何其他的格式,例如 JSON。

1.1.2.2 RESTful API

 

  • 符合 REST 设计风格的 Web API 称为 RESTful API。它从以下三个方面资源进行定义:

  • 直观简短的资源地址:URI,比如:http://example.com/resources

  • 传输的资源:Web 服务接受与返回的互联网媒体类型,比如:JSON,XML,YAML 等。

  • 对资源的操作:Web 服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT 或 DELETE)。

资源 GET PUT POST DELETE
一组资源的URI,比如https://example.com/resources 列出URI,以及该资源组中每个资源的详细信息。 使用给定的一组资源替换当前整组资源。 在本组资源中创建/追加一个新的资源。该操作往往返回新资源的URL。 删除整组资源。
单个资源的URI,比如https://example.com/resources/142 获取指定的资源的详细信息,格式可以自选一个合适的网络媒体类型(比如:XML、JSON等) 替换/创建指定的资源。并将其追加到相应的资源组中。 把指定的资源当做一个资源组,并在其下创建/追加一个新的元素,使其隶属于当前资源。 删除指定的元素。
  • PUT 和 DELETE 方法是幂等方法
  • GET 方法是安全方法(不会对服务器端有修改,因此当然也是幂等的)

 

1.1.2.3 PUT请求类型和POST请求类型的区别
  • PUT 和 POST 均可用于创建或者更新某个资源(例如:添加一个用户、添加一个文件),用哪种请求方式取决我们自己。
  • 我们主要使用是否需要有幂等性来判断到底用 PUT、还是 POST。PUT 是幂等的,也就是将一个对象进行两次 PUT 操作,是不会起作用的。而如果使用 POST,会同时收到两个请求。

1.1.3 HDFS HTTP RESTFUL API

HDFS HTTP RESTFUL API支持以下操作:

1.1.3.1 HTTP GET
  • OPEN (等同于 FileSystem.open)
  • GETFILESTATUS (等同于 FileSystem.getFileStatus)
  • LISTSTATUS (等同于 FileSystem.listStatus)
  • LISTSTATUS_BATCH (等同于 FileSystem.listStatusIterator)
  • GETCONTENTSUMMARY (等同于 FileSystem.getContentSummary)
  • GETQUOTAUSAGE (等同于 FileSystem.getQuotaUsage)
  • GETFILECHECKSUM (等同于 FileSystem.getFileChecksum)
  • GETHOMEDIRECTORY (等同于 FileSystem.getHomeDirectory)
  • GETDELEGATIONTOKEN (等同于 FileSystem.getDelegationToken)
  • GETTRASHROOT (等同于 FileSystem.getTrashRoot)
  • GETXATTRS (等同于 FileSystem.getXAttr)
  • GETXATTRS (等同于 FileSystem.getXAttrs)
  • GETXATTRS (等同于 FileSystem.getXAttrs)
  • LISTXATTRS (等同于 FileSystem.listXAttrs)
  • CHECKACCESS (等同于 FileSystem.access)
  • GETALLSTORAGEPOLICY (等同于 FileSystem.getAllStoragePolicies)
  • GETSTORAGEPOLICY (等同于 FileSystem.getStoragePolicy)
  • GETSNAPSHOTDIFF
  • GETSNAPSHOTTABLEDIRECTORYLIST
  • GETECPOLICY (等同于 HDFSErasureCoding.getErasureCodingPolicy)
  • GETFILEBLOCKLOCATIONS (等同于 FileSystem.getFileBlockLocations)
1.1.3.2 HTTP PUT
  • CREATE (等同于 FileSystem.create)
  • MKDIRS (等同于 FileSystem.mkdirs)
  • CREATESYMLINK (等同于 FileContext.createSymlink)
  • RENAME (等同于 FileSystem.rename)
  • SETREPLICATION (等同于 FileSystem.setReplication)
  • SETOWNER (等同于 FileSystem.setOwner)
  • SETPERMISSION (等同于 FileSystem.setPermission)
  • SETTIMES (等同于 FileSystem.setTimes)
  • RENEWDELEGATIONTOKEN (等同于 DelegationTokenAuthenticator.renewDelegationToken)
  • CANCELDELEGATIONTOKEN (等同于 DelegationTokenAuthenticator.cancelDelegationToken)
  • CREATESNAPSHOT (等同于 FileSystem.createSnapshot)
  • RENAMESNAPSHOT (等同于 FileSystem.renameSnapshot)
  • SETXATTR (等同于 FileSystem.setXAttr)
  • REMOVEXATTR (等同于 FileSystem.removeXAttr)
  • SETSTORAGEPOLICY (等同于 FileSystem.setStoragePolicy)
  • ENABLEECPOLICY (等同于 HDFSErasureCoding.enablePolicy)
  • DISABLEECPOLICY (等同于 HDFSErasureCoding.disablePolicy)
  • SETECPOLICY (等同于 HDFSErasureCoding.setErasureCodingPolicy)
1.1.3.3 HTTP POST
  • APPEND (等同于 FileSystem.append)
  • CONCAT (等同于 FileSystem.concat)
  • TRUNCATE (等同于 FileSystem.truncate)
  • UNSETSTORAGEPOLICY (等同于 FileSystem.unsetStoragePolicy)
  • UNSETECPOLICY (等同于 HDFSErasureCoding.unsetErasureCodingPolicy)
1.1.3.4 HTTP DELETE
  • DELETE (等同于 FileSystem.delete)
  • DELETESNAPSHOT (等同于 FileSystem.deleteSnapshot)

1.1.4 文件系统URL和HTTP URL

WebHDFS 的文件系统 schema 是webhdfs://。WebHDFS 文件系统 URI 具有以下格式:

webhdfs://<HOST>:<HTTP_PORT>/<PATH>

上面的 WebHDFS URI 对应于下面的 HDFS URI。

hdfs://<HOST>:<RPC_PORT>/<PATH>

在RESTAPI 中,在路径中插入前缀/webhdfs/v1,并在末尾追加一个查询。因此,对应的 HTTPURL 具有以下格式:

http://<HOST>:<HTTP_PORT>/webhdfs/v1/<PATH>?op=...

先安装 Postman 进行测试,中文版安装链接(建议不要安装最新版,因为汉化包的更新速度跟不上软件更新速度):https://github.com/hlmd/Postman-cn#1%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85postman
请求URL:http://192.168.68.101:9870/webhdfs/v1/?op=LISTSTATUS
该操作表示要查看根目录下的所有文件以及目录,相当于hdfs dfs -ls /
 
在Postman 中,HDFS 给我们返回了以下信息:

{
    "FileStatuses": {
        "FileStatus": [
            {
                "accessTime": 0,
                "blockSize": 0,
                "childrenNum": 0,
                "fileId": 16558,
                "group": "supergroup",
                "length": 0,
                "modificationTime": 1641885901721,
                "owner": "hadoop",
                "pathSuffix": "benchmarks",
                "permission": "755",
                "replication": 0,
                "storagePolicy": 0,
                "type": "DIRECTORY"
            },
            {
                "accessTime": 0,
                "blockSize": 0,
                "childrenNum": 0,
                "fileId": 16639,
                "group": "supergroup",
                "length": 0,
                "modificationTime": 1641964154596,
                "owner": "hadoop",
                "pathSuffix": "hdfsapi",
                "permission": "755",
                "replication": 0,
                "storagePolicy": 0,
                "type": "DIRECTORY"
            },
            {
                "accessTime": 0,
                "blockSize": 0,
                "childrenNum": 3,
                "fileId": 16386,
                "group": "supergroup",
                "length": 0,
                "modificationTime": 1641967935593,
                "owner": "hadoop",
                "pathSuffix": "input",
                "permission": "755",
                "replication": 0,
                "storagePolicy": 0,
                "type": "DIRECTORY"
            },
            {
                "accessTime": 0,
                "blockSize": 0,
                "childrenNum": 2,
                "fileId": 16388,
                "group": "supergroup",
                "length": 0,
                "modificationTime": 1641879269605,
                "owner": "hadoop",
                "pathSuffix": "tmp",
                "permission": "700",
                "replication": 0,
                "storagePolicy": 0,
                "type": "DIRECTORY"
            },
            {
                "accessTime": 0,
                "blockSize": 0,
                "childrenNum": 1,
                "fileId": 16425,
                "group": "supergroup",
                "length": 0,
                "modificationTime": 1641874559479,
                "owner": "hadoop",
                "pathSuffix": "user",
                "permission": "755",
                "replication": 0,
                "storagePolicy": 0,
                "type": "DIRECTORY"
            }
        ]
    }
}

1.1.5 使用WebHDFS创建并写入到一个文件

1.1.5.1 创建文件

提交 HTTP PUT 请求,而不会自动跟随重定向,也不会发送文件数据。

curl -i -X PUT "http://<HOST>:<PORT>/webhdfs/v1/<PATH>?op=CREATE
                    [&overwrite=<true |false>][&blocksize=<LONG>][&replication=<SHORT>]
                    [&permission=<OCTAL>][&buffersize=<INT>][&noredirect=<true|false>]"

通常,请求被重定向到要写入文件数据的 DataNode。

HTTP/1.1 307 TEMPORARY_REDIRECT
Location: http://<DATANODE>:<PORT>/webhdfs/v1/<PATH>?op=CREATE...
Content-Length: 0

如果不希望自动重定向,则可以设置 noredirected 标志。

HTTP/1.1 200 OK
Content-Type: application/json
{"Location":"http://<DATANODE>:<PORT>/webhdfs/v1/<PATH>?op=CREATE..."}

示例:
/test目录中创建一个名字为webhdfs_api.txt文件,并写入内容。
使用 postman 创建一个请求,设置请求方式为 PUT,请求 url 为:

http://192.168.68.101:9870/webhdfs/v1/test/webhdfs_api.txt?op=CREATE&overwrite=true&replication=2&noredirect=true

HTTP 会响应一个用于上传数据的 URL 链接:

{
    "Location": "http://hadoop1:9864/webhdfs/v1/test/webhdfs_api.txt?op=CREATE&namenoderpcaddress=192.168.68.101:8020&createflag=&createparent=true&overwrite=true&replication=2"
}

1.1.5.2 写入数据

使用 Location 标头中的 URL 提交另一个 HTTP PUT 请求(如果指定了 noredirect,则返回返回的响应),并写入要写入的文件数据。

curl -i -X PUT -T <LOCAL_FILE> "http://<DATANODE>:<PORT>/webhdfs/v1/<PATH>?op=CREATE..."

客户端接收到一个 201 创建的响应,该响应的内容长度为零,位置头中文件的 WebHDFS URI 为:

HTTP/1.1 201 Created
Location: webhdfs://<HOST>:<PORT>/<PATH>
Content-Length: 0

示例:
使用 postman 基于之前返回的 http 响应,上传文件。
 
上传之后,通过 WebUI 发现,已经上传成功。
 
更多操作请参考:https://hadoop.apache.org/docs/r3.3.1/hadoop-project-dist/hadoop-hdfs/WebHDFS.html#Cross-Site_Request_Forgery_Prevention

1.2 HttpFS

  • HttpFS 本质上和 WebHDFS 是一样的,都是提供 HTTP REST API 功能,但它们的区别是 HttpFS 是一个独立于 HadoopNameNode 的服务,它本身就是 Java JettyWeb 应用程序。
  • 因为是可以独立部署的,所以可以对 HttpFS 设置防火墙,而避免 NameNode 暴露在墙外,对一些安全性要求比较高的系统,HttpFS 会更好些。
  • HttpFS 是一种服务器,它提供 REST HTTP 网关,支持所有 HDFS 文件系统操作(读和写)。
  • HttpFS 可用于在运行不同版本 Hadoop(克服RPC版本控制问题)的集群之间传输数据,例如使用 HadoopDiscreCP。
  • HttpFS 可用于在防火墙后面的集群上访问 HDFS 中的数据(HttpFS 服务器充当网关,是允许跨越防火墙进入集群的唯一系统)。
  • HttpFS 可以使用 HTTP 实用程序(例如 curl 和 wget)和来自 Java 以外的其他语言的 HTTP 库 Perl 来访问 HDFS 中的数据。
  • 这个 Webhdfs 客户端文件系统实现可以使用 Hadoop 文件系统命令访问 HttpFS(hdfs dfs)行工具以及使用 Hadoop 文件系统 JavaAPI 的 Java 应用程序。
  • HttpFS 内置了支持 Hadoop 伪身份验证和 HTTP、SPNEGO Kerberos 和其他可插拔身份验证机制的安全性。它还提供 Hadoop 代理用户支持。

1.2.1 HttpFS是如何工作的

  • HttpFS 是一个独立于 HadoopNameNode 的服务。
  • HttpFS 本身就是 Java JettyWeb 应用程序。
  • HttpFS HTTP Web 服务 API 调用是 HTTPREST 调用,映射到 HDFS 文件系统操作。例如,使用 curl/Unix 命令:
$curl ‘http://httpfs-host:14000/webhdfs/v1/user/foo/README.txt?op=OPEN&user.name=foo’
返回HDFS的内容/user/foo/README.txt档案。

$curl ‘http://httpfs-host:14000/webhdfs/v1/user/foo?op=LISTSTATUS&user.name=foo’
返回HDFS的内容/user/foo目录中的JSON格式。

$curl ‘http://httpfs-host:14000/webhdfs/v1/user/foo?op=GETTRASHROOT&user.name=foo’
返回路径/user/foo/.trash,如果/是加密区域,则返回路径。/.Trash/Foo。看见更多细节关于加密区域中的垃圾路径。

$curl -X POST‘http://httpfs-host:14000/webhdfs/v1/user/foo/bar?op=MKDIRS&user.name=foo’
创建HDFS/user/foo/bar目录。

  • HttpFS 默认端口号为 14000

1.2.2 配置Hadoop

编辑 Hadoop 的 core-site.xml,并将运行 HttpFS 服务器的 Unix 用户定义为 proxyuser。例如:

<property>
	<name>hadoop.proxyuser.#HTTPFSUSER#.hosts</name>
	<value>httpfs-host.foo.com</value>
</property>
<property>
	<name>hadoop.proxyuser.#HTTPFSUSER#.groups</name>
	<value>*</value>
</property>

**注意:**替换#HTTPFSUSER#使用将启动 HttpFS 服务器的 Unix 用户。
例如:

<property>
	<name>hadoop.proxyuser.hadoop.hosts</name>
	<value>*</value>
</property>
<property>
	<name>hadoop.proxyuser.hadoop.groups</name>
	<value>*</value>
</property>

1.2.3 重启服务

重启 Hadoop 服务,启动 HttpFS

hdfs --daemon start httpfs

1.2.4 测试HttpFS工作

http://192.168.68.101:14000/webhdfs/v1?user.name=root&op=LISTSTATUS

 

1.2.5 HTTP默认服务

Name Description
/conf Display configuration properties
/jmx Java JMX management interface
/logLevel Get or set log level per class
/logs Display log files
/stacks Display JVM stacks
/static/index.html The static home page

例:http://192.168.68.101:14000/conf?user.name=hadoop

2. 两者区别

  • HttpFS 和 WebHDFS 本质上是一样的,都是提供 HTTP REST API 功能,使得一个集群外的 host 可以不用安装 HADOOP 和 JAVA 环境就可以对集群内的 Hadoop 进行访问,并且 Client 不受语言的限制。但它们的区别是 HttpFS 是一个独立于 HadoopNameNode 的服务,它本身就是 Java JettyWeb 应用程序,而 WebHDFS 是 HDFS 内置的、默认开启的一个服务。

  • HttpHDFS 是可以独立部署的,所以可以对 HttpFS 设置防火墙,而避免 NameNode 暴露在墙外,对一些安全性要求比较高的系统,HttpHDFS 会更好些。

  • WebHDFS 是 HortonWorks 开发的,然后捐给了 Apache;而 HttpFS 是 Cloudera 开发的,也捐给了 Apache。

  • 当 Client 请求某文件时,WebHDFS 会将其重定向到该资源所在的 DataNode,而 HttpFs 相等于一个“网关”,所有的数据先传输到该 HttpFS Server,再由该 HttpFS Server 传输到 Client。

  • 以打开某一文件为例,由于HttpFS会首先将数据传输到 HttpFS Server,再由该 Server 传输到 Client,故当数据量比较大或并发访问次数比较多时,HttpFS Server 将会成为数据传输的瓶颈,出现传输失败的情况。

  • 一般来说两个都可以使用,而且差别不大。但若集群配置了 HA,那就最好使用 HttpFS 了,因为 NameNode 的地址一直在变化,我们是不可能也随时修改脚本里的请求地址的,故在这种情况下直接写 HttpFS Server 的地址好了。