小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
在我们安装好hadoop,并完成相关配置之后,我们会得到一个可以访问分布式文件系统的命令hadoop fs (当然并不只有这一个,还有hadoop dfs,hdfs dfs这两个命令)。
这个命令的风格与我们在用普通 shell 的命令时,基本是一样的。除了令人不爽的 hadoop fs - 部分,和不支持多个参数连写之外,基本与我们的本地文件系统一致。
例如如下一些命令:
hadoop fs -ls xxx //查看相应hdfs目录下的文件信息
hadoop fs -cat x1 x2 x3 ... // 输出多个指定的文件
hadoop fs -rm -r -f xxxx //强制递归删除改路径
注意:
如果我们用 URI 来描述 HDFS 的路径它其实是长这样。
hdfs://xxxx:port/somepath
前面的 hdfs://xxxx:port 一般是从配置中读取的,当然可以手动指定。在使用hadoop的提供的相关文件进行操作时:如果类似linux 的绝对定位,会以 hdfs://xxxx:port 为起点;而如果是使用相对路径,则是以 hdfs://xxxx:port/user/{username} 为起点。
看到这里多少应该会有一点疑惑,这个hdfs应该是能够从外部访问的,否则,它没有必要使用这么长的统一资源定位符。
通过官方文档我们可以知道,hadoop fs 这个 shell 工具仅仅是作为客户端对hdfs进行访问。
我们自己查看下整个调用过程尝试验证,在 hadoop 这个shell 脚本中可以看到当我们运行 fs 子命令时他会实例化这个类 org.apache.hadoop.fs.FsShell ,运行相应的命令。
;;
fs)
HADOOP_CLASSNAME=org.apache.hadoop.fs.FsShell
;;
我们再从这个类出发,可以发现的是,它的子命令基本都是对Java访问hdfs的api (也就是 hdfs-client api)的封装。
那么重点就转移到了,hdfs 的的 Java API 又是如何工作的。
在他的源码中,一层层的调用之后,可以看到一些包含 RPC 字样的使用。
比如这一句:
Writable w = Client.this.getRpcResponse(call, connection, timeout, unit);
其实看到这基本可以确认了,HDFS 与外部交互是通过 RPC 调用。
接下来我们再做一下验证。
在 WINDOWS 电脑上尝试连接远程集群的 HDFS ,并把网络下载的数据直接写入 HDFS 。代码大致如下:
var conf = new Configuration();
var hdfs = FileSystem.get(hdfsServerURI, conf);
var inputStream = xxxx;
IOUtils.copyBytes(inputStream, hdfs.create(new Path(fileName)), conf);
然而,这样大概率会报错说我们没有所谓的 write 写权限。在最简单的情况下,只需要我们把用户名给定即可。方式有很多,例如:设置HADOOP_USER_NAME环境变量;或者在get文件系统的时候给定user参数,把它设置成有权限访问hdfs的用户名称即可。(更强级别的认证这里就不展开了)
在上述代码得到成功运行之后,我们的想法也得到了验证,通过 RPC 调用,HDFS 是与 hadoop 其他组件低耦合的。
当我们需要有 hdfs 的数据时,hdfs 并非需要和我们的机器处于同一台电脑。换句话说,如果我们使用 spark,hadoop 之类的计算框架,他的计算与储存是可以轻松分离的。而这也契合了云原生的相关理念。
更进一步地,在 hadoop 的官方文档中,我们仔细查看可以看到所谓的 hdfs 兼容的文件系统。
其中各大厂商的对象储存基本都是兼容hdfs的,在其中的文档也介绍了如何配置以代替原生的 hdfs 。而且如果我们去看体量比较小的云平台,会发现他们的对象储存是兼容大平台的对象储存服务的,比如 aws s3 。这样的情况下,自然这些对象储存基本都可以用来当作 hdfs 使用。
借助这些,搭建 hdfs 就成了一个可选项了,而非必选项,spark 可以直接分析对象存储中的数据。避免我们在 hdfs 搭建和维护中花费高额地费用,并且可以让我们更灵活地扩展计算能力。