一 HDFS
简介
HDFS
产出背景以及定义2.HDFS
优缺点3.HDFS
组成架构4.HDFS
文件块大小
二 HDFS
的Shell
操作
- 基本语法
bin/hadoop fs
具体命令OR
bin/hdfs dfs
具体命令
dfs
是fs
的实现类。- 常用命令实操
2.1 启动Hadoop
集群(方便后续的测试)sbin/start-dfs.sh sbin/start-yarn.sh
2.2
-help
:输出这个命令参数hadoop fs -help rm
2.3
-ls
: 显示目录信息hadoop fs -ls /
2.4.
-mkdir
:在HDFS
上创建目录hadoop fs -mkdir -p /sanguo/shuguo
2.5
-moveFromLocal
:从本地剪切粘贴到HDFS
hadoop fs -moveFromLocal ./kongming.txt /sanguo/shuguo
2.6
-appendToFile
:追加一个文件到已经存在的文件末尾hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt
2.7
-cat
:显示文件内容hadoop fs -cat /sanguo/shuguo/kongming.txt
2.8
-chgrp
、-chmod
、-chown
:Linux
文件系统中的用法一样,修改文件所属权限hadoop fs -chmod 666 /sanguo/shuguo/kongming.txt hadoop fs -chown xxx:xxx /sanguo/shuguo/kongming.txt
2.9
-copyFromLocal
:从本地文件系统中拷贝文件到HDFS
路径去hadoop fs -copyFromLocal README.txt /
2.10
-copyToLocal
:从HDFS
拷贝到本地hadoop fs -copyToLocal /sanguo/shuguo/kongming.txt ./
2.11
-cp
:从HDFS
的一个路径拷贝到HDFS
的另一个路径hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt
2.12
-mv
:在HDFS
目录中移动文件hadoop fs -mv /zhuge.txt /sanguo/shuguo/
2.13
-get
:等同于copyToLocal
,就是从HDFS
下载文件到本地hadoop fs -get /sanguo/shuguo/kongming.txt ./
2.14
-getmerge
:合并下载多个文件,比如HDFS
的目录/user/xxx/test
下有多个文件:log.1
,log.2
,log.3
,...hadoop fs -getmerge /user/xxx/test/* ./zaiyiqi.txt
2.15
-put
:等同于copyFromLocal
hadoop fs -put ./zaiyiqi.txt /user/xxx/test/
2.16
-tail
:显示一个文件的末尾hadoop fs -tail /sanguo/shuguo/kongming.txt
2.17
-rm
:删除文件或文件夹hadoop fs -rm /user/xxx/test/jinlian2.txt
2.18
-rmdir
:删除空目录hadoop fs -rmdir /test
2.19
-du
: 统计文件夹的大小信息hadoop fs -du -s -h /user/xxx/test
2.20
-setrep
:设置HDFS
中文件的副本数量hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt `这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量。` `因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。`
三 HDFS
客户端操作
1️⃣
HDFS
客户端环境准备
1.根据自己电脑的操作系统拷贝对应的编译后的hadoop jar
包到非中文路径(例如:D:\Develop\hadoop-2.7.2
)
2.配置HADOOP_HOME
环境变量
3.配置Path
环境变量
4.创建一个Maven
工程HdfsClientDemo
5.导入相应的依赖坐标+日志添加<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>jdk.tools</groupId> <artifactId>jdk.tools</artifactId> <version>1.8</version> <scope>system</scope> <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> </dependency> </dependencies>
注意:如果Eclipse/Idea打印不出日志,在控制台上只显示
1.log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell). 2.log4j:WARN Please initialize the log4j system properly. 3.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
需要在项目的
src/main/resources
目录下,新建一个文件,命名为“log4j.properties
”,在文件中填入log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n log4j.appender.logfile=org.apache.log4j.FileAppender log4j.appender.logfile.File=target/spring.log log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
6.创建包名:
com.xxx.hdfs
7.创建HdfsClient
类public class HdfsClient{ @Test public void testMkdirs() throws IOException, InterruptedException, >URISyntaxException{ // 1 获取文件系统 Configuration configuration = new Configuration(); // 配置在集群上运行 // configuration.set("fs.defaultFS", "hdfs://hadoop102:9000"); // FileSystem fs = FileSystem.get(configuration); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 创建目录 fs.mkdirs(new Path("/1108/daxian/banzhang")); // 3 关闭资源 fs.close(); } }
8.执行程序运行时需要配置用户名称
客户端去操作HDFS
时,是有一个用户身份的。默认情况下,HDFS
客户端API
会从JVM
中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=xxx
,xxx
为用户名称。
2️⃣
HDFS
的API
操作
1.HDFS
文件上传@Test public void testCopyFromLocalFile() throws IOException, >InterruptedException, URISyntaxException { // 1 获取文件系统 Configuration configuration = new Configuration(); configuration.set("dfs.replication", "2"); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 上传文件 fs.copyFromLocalFile(new Path("e:/banzhang.txt"), new Path("/banzhang.txt")); // 3 关闭资源 fs.close(); System.out.println("over"); }
将
hdfs-site.xml
拷贝到项目的根目录下<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>
参数优先级排序 : 客户端代码中设置的值 >
ClassPath
下的用户自定义配置文件 > 然后是服务器的默认配置
2.HDFS
文件下载@Test public void testCopyToLocalFile() throws IOException, >InterruptedException, URISyntaxException{ // 1 获取文件系统 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new >URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 执行下载操作 // boolean delSrc 指是否将原文件删除 // Path src 指要下载的文件路径 // Path dst 指将文件下载到的路径 // boolean useRawLocalFileSystem 是否开启文件校验 fs.copyToLocalFile(false, new Path("/banzhang.txt"), new >Path("e:/banhua.txt"), true); // 3 关闭资源 fs.close(); }
HDFS
文件夹删除@Test public void testDelete() throws IOException, InterruptedException, >URISyntaxException{ // 1 获取文件系统 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 执行删除 fs.delete(new Path("/0508/"), true); // 3 关闭资源 fs.close(); }
HDFS
文件名更改@Test public void testRename() throws IOException, InterruptedException, URISyntaxException{ // 1 获取文件系统 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 修改文件名称 fs.rename(new Path("/banzhang.txt"), new Path("/banhua.txt")); // 3 关闭资源 fs.close(); }
HDFS
文件详情查看 (查看文件名称、权限、长度、块信息)@Test public void testListFiles() throws IOException, InterruptedException, URISyntaxException{ // 1获取文件系统 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 获取文件详情 RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true); while(listFiles.hasNext()){ LocatedFileStatus status = listFiles.next(); // 输出详情 // 文件名称 System.out.println(status.getPath().getName()); // 长度 System.out.println(status.getLen()); // 权限 System.out.println(status.getPermission()); // 分组 System.out.println(status.getGroup()); // 获取存储的块信息 BlockLocation[] blockLocations = status.getBlockLocations(); for (BlockLocation blockLocation : blockLocations) { // 获取块存储的主机节点 String[] hosts = blockLocation.getHosts(); for (String host : hosts) { System.out.println(host); } } System.out.println("-----------班长的分割线----------"); } // 3 关闭资源 fs.close(); }
HDFS
文件和文件夹判断@Test public void testListStatus() throws IOException, InterruptedException, URISyntaxException{ // 1 获取文件配置信息 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "xxx"); // 2 判断是文件还是文件夹 FileStatus[] listStatus = fs.listStatus(new Path("/")); for (FileStatus fileStatus : listStatus) { // 如果是文件 if (fileStatus.isFile()) { System.out.println("f:"+fileStatus.getPath().getName()); }else { System.out.println("d:"+fileStatus.getPath().getName()); } } // 3 关闭资源 fs.close(); }
四 HDFS
的数据流
1️⃣
HDFS
写数据流程
1.HDFS
写数据流程1)客户端通过Distributed FileSystem
模块向NameNode
请求上传文件,NameNode
检查目标文件是否已存在,父目录是否存在。
2)NameNode
返回是否可以上传。
3)客户端请求第一个Block
上传到哪几个DataNode
服务器上。
4)NameNode
返回3
个DataNode
节点,分别为dn1
、dn2
、dn3
。
5)客户端通过FSDataOutputStream
模块请求dn1
上传数据,dn1
收到请求会继续调用dn2
,然后dn2
调用dn3
,将这个通信管道建立完成。
6)dn1
、dn2
、dn3
逐级应答客户端。
7)客户端开始往dn1
上传第一个Block
(先从磁盘读取数据放到一个本地内存缓存),以Packet
为单位,dn1
收到一个Packet
就会传给dn2
,dn2
传给dn3
;dn1
每传一个packet
会放入一个应答队列等待应答。
8)当一个Block
传输完成之后,客户端再次请求NameNode
上传第二个Block
的服务器。(重复执行3-7步)。2. 网络拓扑-节点距离计算
在HDFS
写数据的过程中,NameNode
会选择距离待上传数据最近距离的DataNode
接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。
例如,假设有数据中心d1
机架r1
中的节点n1
。该节点可以表示为/d1/r1/n1
。利用这种标记,这里给出四种距离描述3. 机架感知(副本存储节点选择)
1. 官方说明For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on one node in the local rack, another on a different node in the local rack, and the last on a different node in a different rack.
2.
Hadoop2.7.2
副本节点选择
2️⃣
HDFS
读数据流程
1.HDFS
的读数据流程1)客户端通过Distributed FileSystem
向NameNode
请求下载文件,NameNode
通过查询元数据,找到文件块所在的DataNode
地址。
2)挑选一台DataNode
(就近原则,然后随机)服务器,请求读取数据。
3)DataNode
开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet
为单位来做校验)。
4)客户端以Packet
为单位接收,先在本地缓存,然后写入目标文件。
五 HDFS 2.X
新特性
1️⃣集群间数据拷贝
1.scp
实现两个远程主机之间的文件复制# 推 push scp -r hello.txt [root@hadoop103:/user/xxx/hello.txt](mailto:root@hadoop103%253A/user/xxx/hello.txt) # 拉 pull scp -r [root@hadoop103:/user/xxx/hello.txt hello.txt](mailto:root@hadoop103%253A/user/xxx/hello.txt%2520%2520hello.txt) # 是通过本地主机中转实现两个远程主机的文件复制;如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。 scp -r [root@hadoop103:/user/xxx/hello.txt](mailto:root@hadoop103%253A/user/xxx/hello.txt) root@hadoop104:/user/xxx
2.采用
distcp
命令实现两个Hadoop
集群之间的递归数据复制bin/hadoop distcp hdfs://haoop102:9000/user/xxx/hello.txt hdfs://hadoop103:9000/user/xxx/hello.txt
2️⃣小文件存档1. 案例实操
(1)需要启动
YARN
进程start-yarn.sh
(2)归档文件,把/user/xxx/input
目录里面的所有文件归档成一个叫input.har
的归档文件,并把归档后文件存储到/user/xxx/output
路径下。bin/hadoop archive -archiveName input.har –p /user/xxx/input /user/xxx/output
(3)查看归档
hadoop fs -lsr /user/xxx/output/input.har hadoop fs -lsr har:///user/xxx/output/input.har
(4)解归档文件
hadoop fs -cp har:/// user/xxx/output/input.har/* /user/xxx