Hadoop-5-HDFS
1、概述
Hadoop Distributed File System (HDFS™),是一种分布式文件管理系统,用于管理多个机器上的文件
它主要用于存储文件,通过目录树结构来定位文件的位置。适合一次写入,多次读出的场景,不支持文件的修改,所以用它做数据的分析,而不是当作网盘
2、优缺点
【1】优点
- 高容错性。容错性体现在数据保存到多个副本上(DataNode),并且可以通过增加副本的数量(replication),来提高这种特性。并且当一个副本的数据丢失后,它还可以自动恢复
- 大数据量。一是处理数据的量级,可以达到TB、PB的级别。二是文件的数量,能够处理百万以上的规模
- 流式数据。一次写入,多次写出。只能追加,不能修改。保证数据的一致性
- 高可用性。可以将数据节点部署到多个廉价机器上
【2】缺点
- 不能实现低延迟的数据访问。无法做到毫秒级的海量数据存储
- 无法高效地存储多个小文件。处理大量的小文件的存储、目录结构以及块信息,会占用NameNode的大量内存资源。此外小文件存储时的寻址时间会超过其读取时间,这违反了HDFS设计的初衷
- 不能并发写入和随机修改。对于一个文件,在同一时间内只能有一个写入,不允许多个线程同时写入。仅支持文件的追加,不支持文件的修改
3、架构设计
主要由NameNode,DataNode和SecondaryNameNode组成
需要注意的是SecondaryNameNode不是NameNode的热备,所以当NameNode节点挂掉时,其并不能立即替换NameNode并提供服务。SecondaryNameNode是一个用于监控HDFS状态的后台辅助程序,它每隔一段时间就会获取NameNode(HDFS元数据)的快照
4、块
HDFS中的文件在物理上是分块存储(block),块的大小可以通过etc/hadoop/hdfs-site.xml
中的dfs.blocksize
来设置。apache hadoop 2.9.2默认大小为134217728(128MB)
HDFS的块的大小比物理磁盘的块的大小要大,这是为了减少寻址的开销。如果块设置得足够大,那么数据传输的时间要明显地久于块寻址的时间
寻址时间为传输时间的1%时,是最佳状态。计算公式:文件传输时间 = 磁盘寻址时间 / 0.01
块的大小 = 文件传输时间 * 磁盘传输速率
根据公式:假如寻址时间是10s,传输速率是100MB/s,那么块的大小 = 10s / 0.01 * 100MB/s = 100MB
5、命令操作【常用命令】
所有命令都是通过bin/hadoop fs 命令
的方式执行的。注意命令前面都有一个横杠
【1】创建目录
-mkdir -p
,选项p表示递归,和Linux命令一样,不带参数仅创建一级目录
【2】查看目录
-ls -R
,选项R表示递归,它会一直到目录的最里面
【3】删除目录
-rmdir
【4】上传文件
-copyFromLocal /本地文件 /HDFS目录
,复制本地文件到HDFS
-put /本地文件 /HDFS目录
,和copyFromLocal命令一样
-moveFromLocal /本地文件 /HDFS目录
,移动本地文件到HDFS
【5】下载文件
-copyToLocal /HDFS文件 /本地目录
,复制HDFS文件到本地
-get /HDFS文件 /本地目录
,和copyToLocal命令一样
-moveToLocal /HDFS文件 /本地目录
,移动HDFS文件到本地。
Hadoop 2.9.2,提示:moveToLocal: Option ‘-moveToLocal’ is not implemented yet.
【6】追加文件
-appendToFile /本地文件 /HDFS文件
,将本地文件的内容追加到HDFS文件的末端
【7】查看文件
-cat /HDFS文件或目录
,查看文件,可以使用*通配符,和Linux命令一样
-tail -f /HDFS文件
,查看文件末尾,后41行,可以追加f选项,和Linux命令一样
【8】删除文件
-rm -r /HDFS目录或文件
,删除文件或目录,和Linux命令一样
6、Java客户端操作
【1】准备环境
- Java
- Maven
- 和服务端一致的Hadoop,并解压缩到无中文目录
- 下载winutils,并将hadoop-2.8.3/bin目录里的
winutils.exe
复制到解压缩后的hadoop的bin目录当中 - 配置环境变量:
HADOOP_HOME
到解压缩目录 - 打开IDE。一定要先配置好环境变量再打开IDE
【2】MAVEN依赖
<properties>
<!-- 和服务端版本一致 -->
<hadoop.version>2.9.2</hadoop.version>
</properties>
<dependency>
<!-- hadoop-client间接依赖hadoop-common -->
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${hadoop.version}</version>
</dependency>
【3】获取文件系统
通过org.apache.hadoop.fs.FileSystem
对象的静态方法来获取
-
FileSystem get(Configuration conf) throws IOException
,需要传递一个org.apache.hadoop.conf.Configuration
对象,该配置对象的属性,可以从etc/hadoop/core-site.xml
中获取Configuration conf = new Configuration(); // NameNode服务器的IP,9000是默认端口 conf.set("fs.defaultFS", "hdfs://???.???.???.???:9000"); FileSystem fileSystem = null; try { fileSystem = FileSystem.get(conf); System.out.println(fileSystem); } catch (IOException e) { e.printStackTrace(); } finally { if (null != fileSystem) { try { fileSystem.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
FileSystem get(final URI uri, final Configuration conf, String user) throws IOException, InterruptedException
URI uri = null; try { // NameNode服务器的IP,9000是默认端口 uri = new URI("hdfs://???.???.???.???:9000"); } catch (URISyntaxException e) { e.printStackTrace(); return; } Configuration conf = new Configuration(); FileSystem fileSystem = null; try { // 操作文件系统的用户名 fileSystem = FileSystem.get(uri, conf, "???"); System.out.println(fileSystem); } catch (IOException | InterruptedException e) { e.printStackTrace(); } finally { if (null != fileSystem) { try { fileSystem.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
【推荐】
FileSystem get(URI uri, Configuration conf) throws IOException
URI uri = null; try { // NameNode服务器的IP,9000是默认端口 uri = new URI("hdfs://???.???.???.???:9000"); } catch (URISyntaxException e) { e.printStackTrace(); return; } // 操作文件系统的用户名。这句话也可以配置到vm参数当中-DHADOOP_USER_NAME=??? System.setProperty("HADOOP_USER_NAME", "???"); Configuration conf = new Configuration(); FileSystem fileSystem = null; try { fileSystem = FileSystem.get(uri, conf); System.out.println(fileSystem); } catch (IOException e) { e.printStackTrace(); } finally { if (null != fileSystem) { try { fileSystem.close(); } catch (IOException e) { e.printStackTrace(); } } }
【4】参数配置的优先级
通过org.apache.hadoop.conf.Configuration
对象配置参数的优先级是最高的。接着是classpath路径下的配置文件,如core-site.xml
等。最后才是默认配置的参数
【5】创建目录
try {
boolean mkdirs = fileSystem.mkdirs(new Path("/?/?/?"));
System.out.println(mkdirs ? "成功" : "失败");
} catch (IOException e) {
e.printStackTrace();
}
【6】查看目录
try {
RemoteIterator<LocatedFileStatus> remoteIterator = fileSystem.listFiles(new Path("/"), true); // 第二个参数表示是否递归
System.out.println("Permission\tOwner\tGroup\t\tSize\tLast Modified\tPath\t\tReplication");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM-dd HH:mm");
while (remoteIterator.hasNext()) {
LocatedFileStatus locatedFileStatus = remoteIterator.next();
String permission = locatedFileStatus.getPermission().toString();
StringBuilder line = new StringBuilder(permission).append("\t");
String owner = locatedFileStatus.getOwner();
line.append(owner).append("\t");
String group = locatedFileStatus.getGroup();
line.append(group).append("\t");
long size = locatedFileStatus.getLen();
line.append(size).append("\t");
long lastModified = locatedFileStatus.getModificationTime();
String time = simpleDateFormat.format(new Date(lastModified));
line.append(time).append("\t\t");
Path path = locatedFileStatus.getPath();
String pathStr = path