互联网应用必备:分布式文件存储HDFS
wxin55 2024-11-11 14:41 10 浏览 0 评论
1. HDFS概述及设计目标
1.1.什么是DFS
分布式文件系统DFS(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。分布式文件系统的设计基于客户机/服务器模式。一个典型的网络可能包括多个供多用户访问的服务器。另外,对等特性允许一些系统扮演客户机和服务器的双重角色。例如,用户可以“发表”一个允许其他客户机访问的目录,一旦被访问,这个目录对客户机来说就像使用本地驱动器一样。
1.2.什么是HDFS
HDFS(Hadoop Distributed File System),作为GFS(Google File System)的实现,是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了很多便利。
1.2.HDFS的设计目标
(1)非常巨大的分布式文件存储系统;
(2)运行在普通廉价的硬件上;
(3)易扩展、高容错。
1.3.适用、不适用的场景
(1)适用场景
1>高容错性、可构建在廉价机器上;
2>适合批处理;
3>适合大数据处理;
4>流式文件访问。
(2)不适用场景
1>不支持低延迟访问;
2>不适合小文件存储;
3>不支持并发写入。
注:获取HDFS官方文档和更多资料,可以参考以下地址:
(1)官方文档(英文版)
https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
(2)其他资料文档
http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_design.html
2. HDFS架构
HDFS由四部分组成,即HDFS Client、NameNode、DataNode和Secondary NameNode。HDFS是主/从式的架构。一个HDFS集群会有一个NameNode(简称NN),也就是命名节点,该节点作为主服务器存在(master server)。NameNode用于管理文件系统的命名空间以及调节客户访问文件。此外,还会有多个DataNode(简称DN),也就是数据节点,数据节点作为从节点存在(slave server)。通常每一个集群中的DataNode,都会被NameNode所管理,DataNode用于存储数据。
(1)HDFS客户端:就是客户端。
1>提供一些命令来管理、访问 HDFS,比如启动或者关闭HDFS;
2>与 DataNode 交互,读取或者写入数据;读取时,要与 NameNode 交互,获取文件的位置信息;写入 HDFS 的时候,Client 将文件切分成 一个一个的Block,然后进行存储。
(2)NameNode:即Master。
1>管理 HDFS 的名称空间;
2>管理数据块(Block)映射信息;
3>配置副本策略;
4>处理客户端读写请求。
(3)DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作。
1>存储实际的数据块;
2>执行数据块的读/写操作。
(4)Secondary NameNode:并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
1>辅助 NameNode,分担其工作量;
2>定期合并 fsimage和fsedits,并推送给NameNode;
3>在紧急情况下,可辅助恢复 NameNode。
HDFS公开了文件系统名称空间,允许用户将数据存储在文件中,就好比我们平时使用操作系统中的文件系统一样,用户无需关心底层是如何存储数据的。而在底层,一个文件会被分成一个或多个数据块,这些数据库块会被存储在一组数据节点中。在CDH(Cloudera's Distribution, including Apache Hadoop)中数据块的默认大小是128M,这个大小我们可以通过配置文件进行调节。在NameNode上我们可以执行文件系统的命名空间操作,如打开,关闭,重命名文件等。这也决定了数据块到数据节点的映射。
HDFS被设计为可以运行在普通的廉价机器上,而这些机器通常运行着一个Linux操作系统。HDFS是使用java语言编写的,任何支持java的机器都可以运行HDFS。使用高度可移植的java语言编写的HDFS,意味着可以部署在广泛的机器上。一个典型的HDFS集群部署会有一个专门的机器只能运行NameNode,而其他集群中的机器各自运行一个DataNode实例。虽然一台机器上也可以运行多个节点,但是并不建议这么做,除非是学习环境。
3. 读、写文件过程
3.1.从HDFS读取内容
(1)首先调用DistributedFileSystem对象的open方法,其实获取的是一个DistributedFileSystem的实例;
(2)DistributedFileSystem通过RPC(远程过程调用)获得文件的第一批block的locations,同一block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面;
(3)前两步会返回一个FSDataInputStream对象,该对象会被封装成 DFSInputStream 对象,DFSInputStream可以方便地管理DataNode和NameNode数据流。客户端调用read方法,DFSInputStream就会找出离客户端最近的DataNode并连接DataNode;
(4)数据从DataNode源源不断的流向客户端;
(5)如果第一个block块的数据读完了,就会关闭指向第一个block块的DataNode连接,接着读取下一个block块。这些操作对客户端来说是透明的,从客户端的角度来看只是读一个持续不断的流;
(6)如果第一批block都读完了,DFSInputStream就会去NameNode拿下一批blocks的location,然后继续读,如果所有的block块都读完,这时就会关闭掉所有的流。
3.2.向HDFS写入内容
(1)客户端通过调用DistributedFileSystem的create方法,创建一个新的文件;
(2)DistributedFileSystem通过RPC(远程过程调用)调用NameNode,去创建一个没有blocks关联的新文件。创建前,NameNode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode 就会记录下新文件,否则就会抛出IO异常;
(3)前两步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream,DFSOutputStream 可以协调NameNode和 DataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data queue;
(4)DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode又把 packet 输出到第二个 DataNode 中,以此类推;
(5)DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉;
(6)客户端完成写数据后,调用close方法关闭写入流;
(7)DataStreamer 把剩余的包都刷到 pipeline 里,然后等待 ack 信息,收到最后一个ack 后,通知 NameNode把文件标示为已完成。
4. HDFS副本存放机制
在HDFS中,一个文件会被拆分为一个或多个数据块。默认情况下,每个数据块都会有3个副本。每个副本都会被存放在不同的机器上,而且每一个副本都有自己唯一的编号。
NameNode节点选择一个DataNode节点去存储block副本的过程就叫做副本存放,这个过程的策略其实就是在可靠性和读写带宽间的权衡。
《Hadoop权威指南》中副本存放的默认方式:
(1)第一个副本会随机选择,但是不会选择存储过满的节点;
(2)第二个副本放在和第一个副本不同且随机选择的机架上;
(3)第三个和第二个放在同一个机架上的不同节点上;
(4)剩余的副本就完全随机节点了。
如下图:
可以看出这个方案比较合理:
- 可靠性:block存储在两个机架上;
- 写带宽:写操作仅仅穿过一个网络交换机;
- 读操作:选择其中的一个机架去读;
- block分布在整个集群上。
流水线复制
假设HDFS副本系数为3,当本地暂时文件积累到一个数据块大小时,client会从NameNode获取一个列表用于存放副本。然后client开始向第一个DataNode数据传输,第一个DataNode一小部分一小部分地接收数据,将每一部分写入本地仓库,并同一时间传输该部分到列表中的第二个DataNode节点。第二个DataNode也是这样,一小部分一小部分地接收数据,写入本地仓库,并同一时候转发给下一个节点,数据以流水线的方式从前一个DataNode拷贝到下一个DataNode。最后,第三个DataNode接收数据并存储到本地。因此,DataNode能流水线地从前一个节点接收数据,并同一时间转发给下一个节点,数据以流水线的方式从前一个DataNode拷贝到下一个DataNode,并以相反的方向Ack前一个Node。
5. HDFS伪分布式环境搭建
官方安装文档地址如下:
http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.7.0/hadoop-project-dist/hadoop-common/SingleCluster.html
环境描述:
- CentOS7.3
安装CentOS虚拟机可参考https://blog.csdn.net/babyxue/article/details/80970526
- JDK1.8并配置Java环境变量
- Hadoop 2.6.0-cdh5.7.0
- ssh
- rsync
4.1.下载、安装Hadoop
[root@localhost ~]# cd /usr/local/src/
[root@localhost /usr/local/src]# wget http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.7.0.tar.gz
[root@localhost /usr/local/src]# tar -zxvf hadoop-2.6.0-cdh5.7.0.tar.gz -C /usr/local/
注:如果在Linux上下载得很慢的话,可以在windows的迅雷上使用这个链接进行下载。然后再上传到Linux中,这样就会快一些。
解压完后,进入到解压后的目录下,可以看到hadoop的目录结构如下:
[root@localhost /usr/local/src]# cd /usr/local/hadoop-2.6.0-cdh5.7.0/
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0]# ls
bin cloudera examples include libexec NOTICE.txt sbin src
bin-mapreduce1 etc examples-mapreduce1 lib LICENSE.txt README.txt share
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0]#
简单说明一下其中几个目录存放的东西:
- bin目录存放可执行文件
- etc目录存放配置文件
- sbin目录下存放服务的启动命令
- share目录下存放jar包与文档
4.2.配置
以上就算是把hadoop给安装好了,接下来就是编辑配置文件,把JAVA_HOME配置一下:
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0]# cd etc/
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0/etc]# cd hadoop
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0/etc/hadoop]# vim hadoop-env.sh
export JAVA_HOME=/usr/local/jdk1.8/ #
根据你的环境变量进行修改
由于我们要进行的是单节点伪分布式环境的搭建,所以还需要配置两个配置文件,分别是core-site.xml以及hdfs-site.xml,如下:
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0/etc/hadoop]# vim core-site.xml #
增加如下内容
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://192.168.77.130:8020</value> #
指定默认的访问地址以及端口号
</property>
<property>
<name>hadoop.tmp.dir</name> #
指定临时文件所存放的目录
<value>/data/tmp/</value>
</property>
</configuration>
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0/etc/hadoop]# mkdir /data/tmp/
[root@localhost /usr/local/hadoop-2.6.0-cdh5.7.0/etc/hadoop]# vim hdfs-site.xml #
增加如下内容
<configuration>
<property>
<name>dfs.replication</name> #
指定只产生一个副本
<value>1</value>
</property>
</configuration>
然后配置一下密钥对,设置本地免密登录,搭建伪分布式的话这一步是必须的:
[root@localhost ~]# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
Generating public/private dsa key pair.
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:c2:41:89:65:bd:04:9e:3e:3f:f9:a7:51:cd:e9:cf:1e root@localhost
The key's randomart image is:
+--[ DSA 1024]----+
| o=+ |
| .+..o |
| +. . |
| o .. o . |
| = S . + |
| + . . . |
| + . .E |
| o .. o.|
| oo .+|
+-----------------+
[root@localhost ~]# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
[root@localhost ~]# ssh localhost
ssh_exchange_identification: read: Connection reset by peer
[root@localhost ~]#
如上,测试本地免密登录的时候报了个ssh_exchange_identification: read: Connection reset by peer错误,于是着手排查错误,发现是/etc/hosts.allow文件里限制了IP,于是修改一下该配置文件即可,如下:
[root@localhost ~]# vim /etc/hosts.allow #
修改为 sshd: ALL
[root@localhost ~]# service sshd restart
[root@localhost ~]# ssh localhost #
测试登录成功
Last login: Sat Mar 24 21:56:38 2018 from localhost
[root@localhost ~]# logout
Connection to localhost closed.
[root@localhost ~]#
接下来就可以启动HDFS了,不过在启动之前需要先格式化文件系统:
[root@localhost ~]# /usr/local/hadoop-2.6.0-cdh5.7.0/bin/hdfs namenode -format
注:只有第一次启动才需要格式化
使用服务启动脚本启动服务:
[root@localhost ~]# /usr/local/hadoop-2.6.0-cdh5.7.0/sbin/start-dfs.sh
18/03/24 21:59:03 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Starting namenodes on [192.168.77.130]
192.168.77.130: namenode running as process 8928. Stop it first.
localhost: starting datanode, logging to /usr/local/hadoop-2.6.0-cdh5.7.0/logs/hadoop-root-datanode-localhost.out
Starting secondary namenodes [0.0.0.0]
The authenticity of host '0.0.0.0 (0.0.0.0)' can't be established.
ECDSA key fingerprint is 63:74:14:e8:15:4c:45:13:9e:16:56:92:6a:8c:1a:84.
Are you sure you want to continue connecting (yes/no)? yes #
第一次启动会询问是否连接节点
0.0.0.0: Warning: Permanently added '0.0.0.0' (ECDSA) to the list of known hosts.
0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop-2.6.0-cdh5.7.0/logs/hadoop-root-secondarynamenode-localhost.out
18/03/24 21:59:22 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[root@localhost ~]# jps #
检查是否有以下几个进程,如果少了一个都是不成功的
8928 NameNode
9875 Jps
9578 DataNode
9757 SecondaryNameNode
[root@localhost ~]# netstat -lntp |grep java #
检查端口
tcp 0 0 0.0.0.0:50090 0.0.0.0:* LISTEN 9757/java
tcp 0 0 192.168.77.130:8020 0.0.0.0:* LISTEN 8928/java
tcp 0 0 0.0.0.0:50070 0.0.0.0:* LISTEN 8928/java
tcp 0 0 0.0.0.0:50010 0.0.0.0:* LISTEN 9578/java
tcp 0 0 0.0.0.0:50075 0.0.0.0:* LISTEN 9578/java
tcp 0 0 0.0.0.0:50020 0.0.0.0:* LISTEN 9578/java
tcp 0 0 127.0.0.1:53703 0.0.0.0:* LISTEN 9578/java
[root@localhost ~]#
然后将Hadoop的安装目录配置到环境变量中,方便之后使用它的命令:
[root@localhost ~]# vim ~/.bash_profile #
增加以下内容export HADOOP_HOME=/usr/local/hadoop-2.6.0-cdh5.7.0/export PATH=$HADOOP_HOME/bin:$PATH
[root@localhost ~]# source !$source ~/.bash_profile
[root@localhost ~]#
确认服务启动成功后,使用浏览器访问192.168.77.130:50070,会访问到如下页面:
点击Live Nodes查看活着的节点:
如上,可以看到节点的信息。到此,我们伪分布式的hadoop集群就搭建完成了。
注:若无法访问到页面,请检查防火墙状态,可以参考:https://blog.csdn.net/Borntodieee/article/details/80564476
6. HDFS shell操作
HDFS自带有一些shell命令,通过这些命令我们可以去操作HDFS文件系统,这些命令与Linux的命令挺相似的,如果熟悉Linux的命令很容易就可以上手HDFS的命令,关于这些命令的官方文档地址如下:
http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.7.0/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapredCommands.html
以下介绍几个常用的命令:
首先我们创建一个测试文件:
[root@localhost ~]# cd /data/
[root@localhost /data]# vim hello.txt #
随便写一些内容
hadoop welcome
hadoop hdfs mapreduce
hadoop hdfs
[root@localhost /data]#
1.查看文件系统的根目录:
[root@localhost /data]# hdfs dfs -ls /
[root@localhost /data]#
2.将刚刚创建的文件拷贝到文件系统的根目录下:
[root@localhost /data]# hdfs dfs -put ./hello.txt /
[root@localhost /data]# hdfs dfs -ls /
Found 1 items
-rw-r--r-- 1 root supergroup 49 2018-03-24 22:37 /hello.txt
[root@localhost /data]#
3.查看文件内容:
[root@localhost /data]# hdfs dfs -cat /hello.txt
hadoop welcome
hadoop hdfs mapreduce
hadoop hdfs
[root@localhost /data]#
4.创建目录:
[root@localhost /data]# hdfs dfs -mkdir /test
[root@localhost /data]# hdfs dfs -ls /
Found 2 items
-rw-r--r-- 1 root supergroup 49 2018-03-24 22:37 /hello.txt
drwxr-xr-x - root supergroup 0 2018-03-24 22:40 /test
[root@localhost /data]#
5.递归创建目录:
[root@localhost /data]# hdfs dfs -mkdir -p /test/a/b/c
6.递归查看目录:
[root@localhost /data]# hdfs dfs -ls -R /
-rw-r--r-- 1 root supergroup 49 2018-03-24 23:02 /hello.txt
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test/a
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test/a/b
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test/a/b/c
[root@localhost /data]#
7.拷贝文件:
[root@localhost /data]# hdfs dfs -copyFromLocal ./hello.txt /test/a/b
[root@localhost /data]# hdfs dfs -ls -R /
-rw-r--r-- 1 root supergroup 49 2018-03-24 23:02 /hello.txt
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test/a
drwxr-xr-x - root supergroup 0 2018-03-24 23:06 /test/a/b
drwxr-xr-x - root supergroup 0 2018-03-24 23:04 /test/a/b/c
-rw-r--r-- 1 root supergroup 49 2018-03-24 23:06 /test/a/b/hello.txt
[root@localhost /data]#
8.从文件系统中拿出文件:
[root@localhost /data]# hdfs dfs -get /test/a/b/hello.txt
9.删除文件:
[root@localhost /data]# hdfs dfs -rm /hello.txt
Deleted /hello.txt
[root@localhost /data]#
10.删除目录:
[root@localhost /data]# hdfs dfs -rm -R /test
Deleted /test
[root@localhost /data]#
以上就是最为常用的一些操作命令了,如果需要使用其他命令,直接执行hdfs dfs就可以查看到所支持的所有命令。
接下来我们在浏览器里查看文件系统,首先将刚刚删除的文件put回去:
[root@localhost /data]# hdfs dfs -put ./hello.txt /
在浏览器上查看文件系统:
查看文件的信息:
可以看到关于该文件的详细信息:
由于这个文件太小了,所以只有一个数据块。
我们来put一个比较大的文件,例如我们之前使用的Hadoop的安装包:
[root@localhost /data]# cd /usr/local/src/
[root@localhost /usr/local/src]# hdfs dfs -put ./hadoop-2.6.0-cdh5.7.0.tar.gz /
如下,可以看到,这个文件被分为了三个数据块:
注:
(1)若使用hdfs命令之前需要配置hadoop环境变量(/etc/pfofile文件),配置完毕后需要执行 source /etc/profile命令使profile文件生效。
(2)若使用hdfs命令时出现类似于 “util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable”的警告信息,请参照https://blog.csdn.net/l1028386804/article/details/51538611解决。
7. HDFS高可用性分布式搭建
7.1.HDFS高可用简介
在 Hadoop 1.X版本中,NameNode是整个HDFS集群的单点故障(single point of failure,SPOF):每一个HDFS集群只能有一个NameNode节点,一旦NameNode所在服务器宕机或者出现故障将导致整个集群都不可用,除非重启或者开启一个新的Namenode集群才能够恢复可用。NameNode单点故障对HDFS集群的可用性产生影响主要表现在以下两种情况:
(1)当NameNode所在服务器发生未知的异常(例如:服务器宕机)时,在NameNode被重新启动之前整个集群都将不可用。
(2)当NameNode所在服务器执行某些日常维护任务(例如:软件或硬件升级)后重启服务器时,同样会导致HDFS集群在一段时间内不可用。
在Hadoop 2.X 版本中,HDFS引入了双NameNode架构,HA(High Available)通过将两个NameNode分别配置为Active/Passive状态来解决上述问题。处于Active状态的NameNode叫作Active Namenode,处于Passive状态的NameNode叫作Standby Namenode。 Standby Namenode作为Active Namenode的热备份,能够在NameNode发生故障或者由于日常服务器维护需要重启的时候以一种优雅的方式自动切换为Active Namenode。
Active Namenode处理客户端所有的操作请求(读写),Standby Namenode只是作为Active Namenode的Slave尽可能地与Active Namenode保持状态同步,使得在Active Namenode故障时能够快速完成切换。为了使Standby Namenode与Active Namenode数据保持同步,两个Namenode都需要与一组Journal Node进行通信。当Active Namenode执行的任务对namespace有所更改时,会确保将修改日志持久到Journal Node节点中的大部分。Standby Namenode持续监控这些Journal Node,当监测发现这些修改日志有变化时,就会将这些修改应用到自己的namespace,进而保持与Active Namenode中namespace元数据保持一致。当进行故障转移时,Standby Namenode在成为Active Namenode之前,会确保自己已经读取了Journal Node中的所有修改日志,从而保持数据状态与故障发生前一致。为了确保故障转移能够快速完成,Standby Namenode需要维护最新的Block位置信息,即每个Block副本存放在集群中的哪些节点上。为了达到这一点,Datanode同时配置主备两个Namenode,并同时发送Block报告和心跳到两台Namenode。 任何时候只有一个Namenode处于活动状态对HA集群来说至关重要,否则可能出现数据丢失或者数据损坏。当两台Namenode都认为自己的Active Namenode时,会同时尝试写入数据(不会再去检测和同步数据)导致所谓的“裂脑现象”出现。为了达到这个目的并避免出现“裂脑现象”,管理员必须为共享存储配置至少一个(fencing)方法。在宕机期间,如果确定了之前的Active Namenode已经放弃活动状态,fencing进程将负责中断之前的Active Namenode对共享存储的访问和编辑,从而防止它继续对命名空间做出任何进一步的修改,使新的活动节点能够安全地进行故障转移。
7.2.HDFS高可用环境分布式搭建
具体搭建过程可参考https://blog.csdn.net/qq_33247435/article/details/83017380
8. SpringBoot项目集成HDFS
(1)Java操作HDFS主要涉及以下几个主要的类:
Configuration:封装了客户端或者服务器的配置信息;
FileSystem:此类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作通过FileSystem的静态方法get获得该对象,例:FileSystem hdfs = FileSystem.get(conf);
FSDataInputStream:这是HDFS中的输入流,通过由FileSystem的open方法获取;
FSDataOutputStream:这是HDFS中的输出流,通过由FileSystem的create方法获取。
(2)引入pom依赖
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.1.1</version> </dependency> |
(3)使用FileSystem API操作HDFS
具体使用和操作请参照hdfs-demo和
https://blog.csdn.net/linhaiyun_ytdx/article/details/90486277。
相关推荐
- ES6中 Promise的使用场景?(es6promise用法例子)
-
一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...
- JavaScript 对 Promise 并发的处理方法
-
Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...
- Promise的九大方法(promise的实例方法)
-
1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...
- 360前端一面~面试题解析(360前端开发面试题)
-
1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
-
Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
-
看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
-
传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...
- 手写 Promise(手写输入法 中文)
-
前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...
- 什么是 Promise.allSettled()!新手老手都要会?
-
Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...
- 前端面试-关于Promise解析与高频面试题示范
-
Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...
- 宇宙厂:为什么前端离不开 Promise.withResolvers() ?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...
- Promise 新增了一个超实用的 API!
-
在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...
- 一次搞懂 Promise 异步处理(promise 异步顺序执行)
-
PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...
- Promise 核心机制详解(promise机制的实现原理)
-
一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...
- javascript——Promise(js实现promise)
-
1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- ES6中 Promise的使用场景?(es6promise用法例子)
- JavaScript 对 Promise 并发的处理方法
- Promise的九大方法(promise的实例方法)
- 360前端一面~面试题解析(360前端开发面试题)
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
- 手写 Promise(手写输入法 中文)
- 什么是 Promise.allSettled()!新手老手都要会?
- 前端面试-关于Promise解析与高频面试题示范
- 标签列表
-
- hive行转列函数 (63)
- sourcemap文件是什么 (54)
- display none 隐藏后怎么显示 (56)
- 共享锁和排他锁的区别 (51)
- httpservletrequest 获取参数 (64)
- jstl包 (64)
- qsharedmemory (50)
- watch computed (53)
- java中switch (68)
- date.now (55)
- git-bash (56)
- 盒子垂直居中 (68)
- npm是什么命令 (62)
- python中+=代表什么 (70)
- fsimage (51)
- nginx break (61)
- mysql分区表的优缺点 (53)
- centos7切换到图形界面 (55)
- 前端深拷贝 (62)
- kmp模式匹配算法 (57)
- jsjson字符串转json对象 (53)
- jdbc connection (61)
- javascript字符串转换为数字 (54)
- mybatis 使用 (73)
- 安装mysql数据库 (55)