Hadoop——HDFS部分上
一、HDFS概述
1.1 HDFS定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次性写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
1.2 HDFS优缺点
优点:
1、高容错性。数据自动保存多个副本。它通过增加副本的形式,提高容错率。某个副本丢失后可以自动恢复。
2、适合处理大数据。能够处理数据规模达到GB、TB,甚至PB级别的数据。能够处理百万规模以上的文件数量,数量相当之大。
3、可构建在廉价机器上,通过多副本机制,提高可靠性。
缺点:
1、不适合低延时的数据访问,比如毫秒级的存储数据,是做不到的。
2、无法高效地对大量小文件进行存储。存储大量小文件的话,会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存是有限的。而且小文件存储的寻址时间会超过读取时间,这违背了HDFS设计目标。
3、不支持并发写入,文件随机修改,一个文件只能有一个写,不允许多个进程同时写。同时仅支持数据追加(append),不支持文件的随机修改。
1.3 HDFS组成架构
二、HDFS的Shell操作
2.1基本语法
hadoop fs [具体命令] 或者 hdfs dfs [具体命令]。
2.2 命令大全
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] <localsrc> ... <dst>]
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] <path> ...]
[-cp [-f] [-p] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] <path> ...]
[-expunge]
[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getmerge [-nl] <src> <localdst>]
[-help [cmd ...]]
[-ls [-d] [-h] [-R] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touchz <path> ...]
[-usage [cmd ...]]
其中的 -setrep
:设置HDFS中文件的副本数量
hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt
这里设置的副本数只是记录在 NameNode 的元数据中,是否真的会有这么多副本,还得看 DataNode 的数量。因为目前只有 3 台设备,最多也就 3 个副本,只有节点数的增加到 10 台时,副本数才能达到 10 。
三、HDFS客户端操作
3.1 HDFS客户端环境准备
3.1.1 下载Hadoop3.1.0的windows依赖,并配置环境变量。
可以将bin目录下hadoop.dll和winutils.exe放到C:/windows/system32目录下。
windows本地运行mr程序时(不提交到yarn,运行在jvm靠线程执行),很容易报错,所以将两个文件添加到bin目录下。
hadoop.dll防止报nativeio异常、winutils.exe没有的话可能报空指针异常。
3.1.2 在IDEA中创建maven工程,并导入相应的依赖坐标和日志添加。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
在项目的src/main/resources目录下,新建一个文件,命名为“log4j2.xml”,在文件中填入
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
<Appenders>
<!-- 类型名为Console,名称为必须属性 -->
<Appender type="Console" name="STDOUT">
<!-- 布局为PatternLayout的方式,
输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
<Layout type="PatternLayout"
pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
</Appender>
</Appenders>
<Loggers>
<!-- 可加性为false -->
<Logger name="test" level="info" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<!-- root loggerConfig设置 -->
<Root level="info">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
3.2 HDFS的API操作
3.2.1 用户名的传递和获得HDFS的操作
客户端去操作HDFS时,是有一个用户身份的。
默认情况下,HDFS客户端API会从JVM中获取一个参数来作为自己的用户身份:
-DHADOOP_USER_NAME=[HDFS文件系统的用户名]
如果不设置的话就会默认以Windows的用户名来作为自己的身份。
用户名也可以在代码中进行配置
以下代码为执行业务前的必须操作,将其提取放在@Before注解的before()方法中。
public class HDFSDemo {
private FileSystem fs;
@Before
public void before() throws URISyntaxException, IOException, InterruptedException {
/**
* 1、创建客户端对象
*
* get(final URI uri, final Configuration conf, final String user)
*
* uri:HDFS的地址
* conf:配置的参数
* user:用来操作HDFS的用户名
*/
URI uri = new URI("hdfs://hadoop102:8020");
Configuration conf = new Configuration();
fs=FileSystem.get(uri, conf,"[用户名]");
}
}
业务结束后关闭资源,将其放在@After注解的after()方法中。
@After
public void after() {
//关闭资源
try{
if(fs!=null){
fs.close();
}
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(fs!=null) {
fs.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
3.2.2 下载操作
第4个参数是查看校验和的
/**
* 从HDFS下载文件到本地
* @throws IOException
*/
@Test
public void testDownLoad() throws IOException {
fs.copyToLocalFile(false,
new Path("/input/log4j2.xml"),
new Path("D:\\Study_Code\\HdfsClientDemo\\src\\main\\resources\\download"),
true);
}
3.2.3 将HDFS上的文件删除
第一个参数是文件在HDFS上的路径。
第二个参数,如果删文件的话,true或false都可以,删除目录需要成true。
/**
* 将HDFS上的文件删除
* @throws IOException
*/
@Test
public void testDel() throws IOException {
fs.delete(new Path("/input/log4j2.xml"),true);
}
3.2.4 将HDFS上的文件移动或改名
此方法既可以改名也可以剪切文件。
/**
* 将HDFS上的文件移动或改名
*/
@Test
public void testMoveAndRename() throws IOException {
// fs.rename(new Path("/input/log4j2.xml"),new Path("/log4j2.xml"));
// fs.rename(new Path("/log4j2.xml"),new Path("/input/log4j2.xml"));
fs.rename(new Path("/input/log4j2.xml"),new Path("/input/log.xml"));
}
3.2.5 HDFS文件和文件夹判断
/**
* HDFS文件和文件夹判断
*/
@Test
public void testListStatus() throws IOException {
FileStatus[] fileStatus = fs.listStatus(new Path("/"));
for (FileStatus status : fileStatus) {
if(status.isFile()) System.out.println("f: "+status.getPath().getName());
else if(status.isDirectory()) System.out.println("d: "+status.getPath().getName());
else System.out.println("ERROR!!!");
}
}
}
3.2.6 从HDFS中获取文件的细节信息
/**
* 从HDFS中获取文件的细节信息
* @throws IOException
*/
@Test
public void testFileDetails() throws IOException {
RemoteIterator<LocatedFileStatus> fileList = fs.listFiles(new Path("/input"),true);
while(fileList.hasNext()){
LocatedFileStatus fileStatus = fileList.next();
System.out.println("==="+fileStatus.getPath().getName()+"===");
System.out.println("副本数: "+fileStatus.getReplication());
System.out.println("块大小: "+fileStatus.getBlockSize());
System.out.println("文件大小: "+fileStatus.getLen());
BlockLocation[] blockLocations=fileStatus.getBlockLocations();
System.out.println("块信息 :"+Arrays.toString(blockLocations));
}
}