一 HDFS简单介绍
1.1 HDFS产生背景
随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
1.2 HDFS概念
HDFS**,它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的**,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改(也是可以修改的,但是不建议)。适合用来做数据分析,并不适合用来做网盘应用。
1.3 HDFS 优缺点
1.3.1 优点
1)高容错性
(1)数据自动保存多个副本。它通过增加副本的形式,提高容错性。
(2)某一个副本丢失以后,它可以自动恢复,这是由 HDFS 内部机制实现的,我们不必关心。
2)适合大数据处理
(1)数据规模:能够处理数据规模达到 GB、TB、甚至PB级别的数据。(因为他会切块存储,所以可以存储大文件-**参见HDFS**写数据流程)
(2)文件规模:能够处理百万规模以上的文件数量,数量相当之大。
3)流式数据访问**(一点一点的处理数据,而不是一次性读取整个数据,这样会极大消耗内存)**
(1)一次写入,多次读取,不能修改,只能追加。
(2)它能保证数据的一致性。
4)可构建在廉价机器上
(1)它通过多副本机制,提高可靠性。
(2)它提供了容错和恢复机制。比如某一个副本丢失,可以通过其它副本来恢复。
1.3.2 缺点
1)不适合低延时数据访问
(1)比如毫秒级的来存储数据,这是不行的,它做不到。
(2)它适合高吞吐率的场景,就是在某一时间内写入大量的数据。但是它在低延时的情况下是不行的,比如毫秒级以内读取数据,这样它是很难做到的。
2)无法高效的对大量小文件进行存储(HDFS默认的最基本的存储单位是128M的数据块。)
(1)存储大量小文件;)的话,它会占用 NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,因为NameNode的内存总是有限的。
(2)小文件存储的寻道时间会超过读取时间,它违反了HDFS的设计目标。
3)并发写入、文件随机修改
(1)一个文件只能有一个写,不允许多个线程同时写。
(2)仅支持数据 append(追加),不支持文件的随机修改。
1.4 HDFS架构
HDFS的架构图
这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。下面我们分别介绍这四个组成部分。
1)Client:就是客户端。
(1)文件切分。文件上传 HDFS 的时候,Client 将文件切分成一个一个的Block,然后进行存储。
(2)与NameNode交互,获取文件的位置信息。
(3)与DataNode交互,读取或者写入数据。
(4)Client提供一些命令来管理HDFS,比如启动或者关闭HDFS。
(5)Client可以通过一些命令来访问HDFS。
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。
1.5 HDFS 文件块大小
HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M。
HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因而,传输一个由多个块组成的文件的时间取决于磁盘传输速率。
如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小设置约为100MB。默认的块大小128MB。
块的大小:
|
块大小取决于磁盘传输速率
二 HFDS命令行操作
操作HDFS的命令其实有三个:
Hadoop fs:使用面最广,可以操作任何文件系统。
hadoop dfs与hdfs dfs:只能操作HDFS文件系统相关(包括与Local FS间的操作),前者已经Deprecated,一般使用后者。
推荐使用:hadoop fs
1)基本语法
bin/hadoop fs 具体命令
2)参数大全
[kingge@hadoop102 hadoop-2.7.2]$ bin/hadoop fs
[-appendToFile
|
3)常用命令
(0)启动Hadoop集群(方便后续的测试)
[kingge@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[kingge@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh
(1)-help:输出这个命令参数
[kingge@hadoop102 hadoop-2.7.2]$ bin/hdfs dfs -help rm
(2)-ls: 显示目录信息
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -ls /
(3)-mkdir:在hdfs上创建目录
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -mkdir -p /user/kingge/test
(4)-moveFromLocal从本地剪切粘贴到hdfs
[kingge@hadoop102 hadoop-2.7.2]$ touch jinlian.txt
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -moveFromLocal ./jinlian.txt /user/kingge/test
(5)–appendToFile :追加一个文件到已经存在的文件末尾
[kingge@hadoop102 hadoop-2.7.2]$ touch ximen.txt
[kingge@hadoop102 hadoop-2.7.2]$ vi ximen.txt
输入
wo ai jinlian
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -appendToFile ximen.txt /user/kingge/test/jinlian.txt
(6)-cat :显示文件内容
(7)-tail:显示一个文件的末尾
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -tail /user/kingge/test/jinlian.txt
(8)-chgrp 、-chmod、-chown:linux文件系统中的用法一样,修改文件所属权限
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -chmod 666 /hello.txt
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -chown someuser:somegrp /hello.txt
(9)-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -copyFromLocal README.txt /user/kingge/test
(10)-copyToLocal:从hdfs拷贝到本地
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -copyToLocal /user/kingge/test/jinlian.txt ./jinlian.txt
(11)-cp :从hdfs的一个路径拷贝到hdfs的另一个路径
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -cp /user/kingge/test/jinlian.txt /jinlian2.txt
(12)-mv:在hdfs目录中移动文件
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -mv /jinlian2.txt /user/kingge/test/
(13)-get:等同于copyToLocal,就是从hdfs下载文件到本地
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -get /user/kingge/test/jinlian2.txt ./
(14)-getmerge :合并下载多个文件,比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,…
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -getmerge /user/kingge/test/* ./zaiyiqi.txt
(15)-put:等同于copyFromLocal
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -put ./zaiyiqi.txt /user/kingge/test/
(16)-rm:删除文件或文件夹
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -rm /user/kingge/test/jinlian2.txt
(17)-rmdir:删除空目录
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -mkdir /test
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -rmdir /test
(18)-df :统计文件系统的可用空间信息
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -df -h /
(19)-du统计文件夹的大小信息
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -du -s -h /user/kingge/test
2.7 K /user/kingge/test ###查看文件夹下文件总大小
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -du -h /user/kingge/test
1.3 K /user/kingge/test/README.txt
15 /user/kingge/test/jinlian.txt
1.4 K /user/kingge/test/zaiyiqi.txt
##查看文件夹下各个文件大小
(20)-setrep:设置hdfs中文件的副本数量
[kingge@hadoop102 hadoop-2.7.2]$ hadoop fs -setrep 2 /user/kingge/test/jinlian.txt
这里设置的副本数只是记录在namenode的元数据中,是否真的会有这么多副本,还得看datanode的数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。
三 HDFS客户端操作-eclipse
3.1 Eclipse环境准备
注意:以下操作,是在hadoop集群中中进行的,也就是说,需要先启动linux的hadoop集群
3.1.1 jar包准备
1)解压hadoop-2.7.2.tar.gz到非中文目录
2)进入share文件夹,查找所有jar包,并把jar包拷贝到_lib文件夹下
3)在全部jar包中查找sources.jar,并剪切到_source文件夹。
4)在全部jar包中查找tests.jar,并剪切到_test文件夹。
3.1.2 Eclipse准备
1)配置HADOOP_HOME环境变量
2)采用Hadoop编译后的bin 、lib两个文件夹(如果不生效,重新启动eclipse)
3)创建第一个java工程
4)导入 编译后目录的jar包(可以在文章下方回复我,我私信给你们)
public class HdfsClientDemo1 { public static void main(String[] args) throws Exception { // 1 获取文件系统 Configuration configuration = new Configuration(); // 配置在集群上运行 configuration.set(“fs.defaultFS”, “hdfs://hadoop102:9000”); FileSystem fileSystem = FileSystem.get(configuration); // 直接配置访问集群的路径和访问集群的用户名称 // FileSystem fileSystem = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 2 把本地文件上传到文件系统中 fileSystem.copyFromLocalFile(new Path(“f:/hello.txt”), new Path(“/hello1.copy.txt”)); // 3 关闭资源 fileSystem.close(); System.out.println(“over”); } }
|
4)执行程序
运行时需要配置用户名称
客户端去操作hdfs时,是有一个用户身份的。默认情况下,hdfs客户端api会从jvm中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=kingge,kingge为用户名称。
3.2 通过API操作HDFS
3.2.1 HDFS获取文件系统
1)详细代码
@Test public void initHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); // 2 获取文件系统 FileSystem fs = FileSystem.get(configuration); // 3 打印文件系统 System.out.println(fs.toString()); }
|
3.2.2 HDFS文件上传
|
@Test public void putFileToHDFS() throws Exception{ // 1 创建配置信息对象 // new Configuration();的时候,它就会去加载jar包中的hdfs-default.xml // 然后再加载classpath下的hdfs-site.xml Configuration configuration = new Configuration(); // 2 设置参数 // 参数优先级: 1、客户端代码中设置的值 2、classpath下的用户自定义配置文件 3、然后是服务器的默认配置 configuration.set(“dfs.replication”, “2”); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 3 创建要上传文件所在的本地路径 Path src = new Path(“e:/hello.txt”); // 4 创建要上传到hdfs的目标路径 Path dst = new Path(“hdfs://hadoop102:9000/user/atguigu/hello.txt”); // 5 拷贝文件 fs.copyFromLocalFile(src, dst); fs.close(); }
2)将core-site.xml拷贝到项目的根目录下
<?xml version=”1.0” encoding=”UTF-8”?> <?xml-stylesheet type=”text/xsl” href=”configuration.xsl”?>
|
3)将hdfs-site.xml拷贝到项目的根目录下
<?xml version=”1.0” encoding=”UTF-8”?> <?xml-stylesheet type=”text/xsl” href=”configuration.xsl”?>
|
4)测试参数优先级
参数优先级: 1**、客户端代码中设置的值 2、classpath下的用户自定义配置文件 3**、然后是服务器的默认配置
3.2.3 HDFS文件下载
@Test public void getFileFromHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // fs.copyToLocalFile(new Path(“hdfs://hadoop102:9000/user/atguigu/hello.txt”), new Path(“d:/hello.txt”)); // boolean delSrc 指是否将原文件删除 // Path src 指要下载的文件路径 // Path dst 指将文件下载到的路径 // boolean useRawLocalFileSystem 是否开启文件效验 // 2 下载文件 fs.copyToLocalFile(false, new Path(“hdfs://hadoop102:9000/user/atguigu/hello.txt”), new Path(“e:/hellocopy.txt”), true); fs.close(); }
|
3.2.4 HDFS目录创建
@Test public void mkdirAtHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); //2 创建目录 fs.mkdirs(new Path(“hdfs://hadoop102:9000/user/atguigu/output”)); }
|
3.2.5 HDFS文件夹删除
|
@Test public void deleteAtHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); //2 删除文件夹 ,如果是非空文件夹,参数2是否递归删除,true递归 fs.delete(new Path(“hdfs://hadoop102:9000/user/atguigu/output”), true); }
3.2.6 HDFS文件名更改
@Test public void renameAtHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); //2 重命名文件或文件夹 fs.rename(new Path(“hdfs://hadoop102:9000/user/atguigu/hello.txt”), new Path(“hdfs://hadoop102:9000/user/atguigu/hellonihao.txt”)); }
|
3.2.7 HDFS文件详情查看
查看文件名称、权限、长度、块信息-不是文件夹,是文件
@Test public void readListFiles() throws Exception { // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 思考:为什么返回迭代器,而不是List之类的容器 RemoteIterator
|
3.2.8 HDFS文件和文件夹判断
不支持递归,只能查询当前某个目录下的文件或者或者文件夹,然后判断
|
@Test public void findAtHDFS() throws Exception, IllegalArgumentException, IOException{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 2 获取查询路径下的文件状态信息 FileStatus[] listStatus = fs.listStatus(new Path(“/“)); // 3 遍历所有文件状态 for (FileStatus status : listStatus) { if (status.isFile()) { System.out.println(“f–” + status.getPath().getName()); } else { System.out.println(“d–” + status.getPath().getName()); } } }
3.3 通过IO流操作HDFS
3.3.1 HDFS文件上传
@Test public void putFileToHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 2 创建输入流 FileInputStream inStream = new FileInputStream(new File(“e:/hello.txt”)); // 3 获取输出路径 String putFileName = “hdfs://hadoop102:9000/user/atguigu/hello1.txt”; Path writePath = new Path(putFileName); // 4 创建输出流 FSDataOutputStream outStream = fs.create(writePath); // 5 流对接 try{ IOUtils.copyBytes(inStream, outStream, 4096, false); }catch(Exception e){ e.printStackTrace(); }finally{ IOUtils.closeStream(inStream); IOUtils.closeStream(outStream); } }
|
3.3.2 HDFS文件下载
@Test public void getFileToHDFS() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”),configuration, “atguigu”); // 2 获取读取文件路径 String filename = “hdfs://hadoop102:9000/user/atguigu/hello1.txt”; // 3 创建读取path Path readPath = new Path(filename); // 4 创建输入流 FSDataInputStream inStream = fs.open(readPath); // 5 流对接输出到控制台 try{ IOUtils.copyBytes(inStream, System.out, 4096, false); }catch(Exception e){ e.printStackTrace(); }finally{ IOUtils.closeStream(inStream); } }
|
3.3.3 定位文件读取
1)下载第一块
@Test // 定位下载第一块内容 public void readFileSeek1() throws Exception { // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”), configuration, “atguigu”); // 2 获取输入流路径 Path path = new Path(“hdfs://hadoop102:9000/user/atguigu/tmp/hadoop-2.7.2.tar.gz”); // 3 打开输入流 FSDataInputStream fis = fs.open(path); // 4 创建输出流 FileOutputStream fos = new FileOutputStream(“e:/hadoop-2.7.2.tar.gz.part1”); // 5 流对接 byte[] buf = new byte[1024]; for (int i = 0; i < 128 1024; i++) { fis.read(buf); fos.write(buf); } // 6 关闭流 IOUtils.closeStream(fis); IOUtils.closeStream*(fos); }
|
2)下载第二块
@Test // 定位下载第二块内容 public void readFileSeek2() throws Exception{ // 1 创建配置信息对象 Configuration configuration = new Configuration(); FileSystem fs = FileSystem.get(new URI(“hdfs://hadoop102:9000”), configuration, “atguigu”); // 2 获取输入流路径 Path path = new Path(“hdfs://hadoop102:9000/user/atguigu/tmp/hadoop-2.7.2.tar.gz”); // 3 打开输入流 FSDataInputStream fis = fs.open(path); // 4 创建输出流 FileOutputStream fos = new FileOutputStream(“e:/hadoop-2.7.2.tar.gz.part2”); // 5 定位偏移量(第二块的首位) fis.seek(1024 1024 128); // 6 流对接 IOUtils.copyBytes(fis, fos, 1024); // 7 关闭流 IOUtils.closeStream(fis); IOUtils.closeStream(fos); }
|
3)合并文件
在window命令窗口中执行
type hadoop-2.7.2.tar.gz.part2 >> hadoop-2.7.2.tar.gz.part1
解压,发现,就是我们上传的压缩文件。