Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)

* HDFS的工作原理是答辩重点(块、元数据、主/从节点SecondaryNameNode,FsImage、EditImage、存取策略/规则、数据出错与恢复、读写过程)

集群和分布式概念:

  • 集群:集群就是逻辑上处理同一任务的机器集合,可以属于同一机房,也可分属不同的机房
  • 分布式:分布式文件系统把文件分布存储到多个计算机节点上,成千上万的计算机节点构成计算机集群

集群就是逻辑上处理同一任务的机器集合,可以属于同一机房,也可分属不同的机房。分布式这个概念可以运行在某个集群里面,某个集群也可作为分布式概念的一个节点。一句话,就是:“分头做事”与“一堆人”的区别。

分布式文件系统的结构:

分布式文件系统在物理结构上是由计算机集群中的多个节点构成的,这些节点分为两类,一类叫“主节点”(Master Node)或者也被称为“名称结点”(NameNode),另一类叫“从节点”(Slave Node)或者也被称为“数据节点”(DataNode)。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第1张图片 大规模文件系统的整体结构

HDFS是存储数据的地方,就像电脑的硬盘一样,文件都存储在这个上面,MapReduce是对数据进行处理计算的,它有个特点就是不管多大的数据只要给它时间它就能把数据跑完,但是时间可能不是很快,所以它叫数据的批处理。YARN是体现Hadoop平台概念的重要组件,有了它大数据生态体系的其它软件就能在hadoop上运行了,这样就能更好的利用HDFS大存储的优势和节省更多的资源,比如我们就不用再单独建一个spark的集群了,让它直接跑在现有的hadoop yarn上面就可以了

HDFS架构

HDFS:分布式存储

HDFS优点:

  • 高容错性:数据自动保存多个副本、副本丢失后、自动恢复
  • 适合批处理:移动计算而非数据,数据位置暴露给计算框架
  • 适合大数据处理:GBTB甚至PB级数据,百万规模以上的文件数量
  • 可构建在廉价机器上:通过多副本提高可靠性,提供了容错和恢复机制

HDFS缺点:大量小文件存储在hdfs上时,压缩成一个文件(网盘不允许文件修改:百度、360网盘,国内80%的网盘都是基于hadoop

  • 低延迟数据访问:比如毫秒级,低延迟与高吞吐率
  • 小文件存储:占用NameNode大量内存,寻道时间超过读取时间
  • 并发写入、文件随机修改:一个文件只能有一个写着,仅支持append
Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第2张图片 HDFS架构

HDFS 采用Master/Slave的架构来存储数据,这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode。下面我们分别介绍这四个组成部分。

:HDFS块默认大小为64MB

块(Block)HDFS的文件被分成块进行存储,块是文件存储处理的逻辑单元

在HDFS所有的文件在存储的时候都是把文件切分成相同固定大小的数据块,每个块默认大小64MB字节。当文件传过来之后,系统把它拆分成块进行存储,若文件大小不到64MB,则单独存成一个block,存储到不同节点上, 默认情况下每个block都有三个副本。从管理上看,块是整个文件存储、处理的逻辑单元。我们进行的文件备份、查找也都是按照块来处理的。

注意: Block大小和副本数通过Client端上传文件时设置,文件上传成功后副本数可以变更,Block Size不可变更。

HDFS块存储优势:

支持大规模文件存储:一个大规模文件可以被分拆成若干个文件块,不同的文件块可以被分发到不同的节点上。

简化系统设计:简化了存储管理、方便了元数据的管理。

适合数据备份:每个文件块都可以冗余存储到多个节点上,大大提高了系统的容错性和可用性。

节点:NameNode和DataNode

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第3张图片

NameNode(名称节点)是管理节点,存放元数据:①文件与数据块的映射表  ②数据块与数据节点的映射表

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第4张图片 HDFS体系结构

NameNode是管理节点,主要存放元数据。元数据包括两个部分:一个是文件和数据块的映射表;另一个是数据块和数据节点的映射表。客户如果一个访问请求,那么他NameNode读取元数据 NameNode返回相关的信息,说明这个文件是存放在哪一些节点上面,于是他去向这些节点去读取数据块获取到数据块之后再进行组装,拼装成之前想要的文件HDFS里的主节点NameNode

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第5张图片 数据结构
  • NameNode负责管理分布式文件系统的命名空间(Namespace),保存了两个核心的数据结构,即FsImageEditLog
  • FsImage用于维护文件系统树以及文件树中所有的文件和文件夹的元数据
  • 操作日志文件EditLog中记录了所有针对文件的创建、删除、重命名等操作
  • 名称节点记录了每个文件中各个块所在的数据节点的位置信息

名称节点运行期间EditLog不断变大的问题,靠SecondaryNameNode第二名称节点解决。

第二名称节点HDFS架构中的一个组成部分,它是用来保存名称节点中对HDFS 元数据信息的备份,并减少名称节点重启的时间。SecondaryNameNode一般是单独运行在一台机器上。

在名称节点运行期间,HDFS的所有更新操作都是直接写到EditLog中,久而久之, EditLog文件将会变得很大

虽然这对名称节点运行时候是没有什么明显影响的,但是,当名称节点重启的时候,名称节点需要先将FsImage里面的所有内容映像到内存中,然后再一条一条地执行EditLog中的记录,当EditLog文件非常大的时候,会导致名称节点启动操作非常慢,而在这段时间内HDFS系统处于安全模式,一直无法对外提供写操作,影响了用户的使用。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第6张图片 SecondaryNameNode

SecondaryNameNode的工作情况:

  • 1SecondaryNameNode会定期和NameNode通信,请求其停止使用EditLog文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;
  • 2SecondaryNameNode通过HTTP GET方式从NameNode上获取到FsImageEditLog文件,并下载到本地的相应目录下;
  • 3SecondaryNameNode将下载下来的FsImage载入到内存,然后一条一条地执行EditLog文件中的各项更新操作,使得内存中的FsImage保持最新;这个过程就是EditLogFsImage文件合并;
  • 4SecondaryNameNode执行完(3)操作之后,会通过post方式将新的FsImage文件发送到NameNode节点上
  • 5NameNode将从SecondaryNameNode接收到的新的FsImage替换旧的FsImage文件,同时将edit.new替换EditLog文件,通过这个过程EditLog就变小了

DataNode(数据节点)HDFS的工作节点,存放数据块:

数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块的列表;每个数据节点中的数据会被保存在各自节点的本地Linux文件系统中。

第二类节点DataNodeDataNodeHDFS里的工作节点,它是用来存放真正数据块的

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第7张图片

 如刚才介绍主节点的图所示,左边的机架13DataNode节点的机加2DataNode节点。这些DataNode是存放真正数据块。在这里补充说明一下,Hadoop为了保证节点因电力、网络的原因导致宕机,在集群的管理上引入机架的概念,用物理位置来提升集群的容灾能力。

HDFS体系结构:

  • HDFS采用了主从(Master/Slave结构模型
  • HDFS集群包括一个名称节点(NameNode)和若干个数据节点(DataNode

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第8张图片

 名称节点作为中心服务器,负责管理文件系统的命名空间及客户端对文件的访问。集群中的数据节点一般是一个节点运行一个数据节点进程,负责处理文件系统客户端的读/写请求,在名称节点的统一调度下进行数据块的创建、删除和复制等操作。每个数据节点的数据实际上是保存在本地Linux文件系统中的。

HDFS要实现以下目标:

  • 兼容廉价的硬件设备
  • 流数据读写
  • 大数据集
  • 简单的文件模型
  • 强大的跨平台兼容性

HDFS的局限性:

  • 不适合低延迟数据访问
  • 无法高效存储大量小文件
  • 不支持多用户写入及任意修改文件

HDFShadoop的分布式文件系统,它和现有的分布式文件系统有很多共同特点,但同时区别也很明显,在设计HDFS的时候, Doug Cutting主要考虑了5个方面的因素:

  • 第一个因素是:硬件故障是常态,而非偶然因素;hdfs可能有成千上万台服务器组成,每个服务器上都存储着文件系统的部分数据;每台服务器都可能出现故障而无法工作,自动快速检测错误,并避免影响HDFS的运行,是他设计时候的最核心目标。
  • 二个因素是:HDFS是用于批处理的应用场景,与交互式访问场景的低时延任务目标不同,数据批处理任务更多考虑的是吞吐量。HDFS采用了最高效的访问模式,也就是经常说的流式数据访问。
  • 三是:尽量减少数据传输,在hadoop这样基于集群的分布式系统中,计算节点可以很方便地扩充,它能提供的计算能力可以说是无限的;但是,假如数据需要在计算机之间传输的话,网络带宽就会成为瓶颈,为了突破这个限制,doug cutting决定,由存储数据的这个节点,负责它所存储的这部分数据的运算,这样就可以减少数据在网络上的传输,降低对网络带宽的需求。与以往把数据传输到计算单元相比,hdfs实现了把运算能力赋予数据单元。
  • 四是:HDFS设计了简单数据一致性模型,为了在确保高吞吐量数据访问的同时,保证数据的一致性,hdfs采用一次写入,多次读取的文件访问模型,也就是说一旦一个文件创建、写入、关闭之后,它的内容就不会再进行修改,这种模式简化了数据一致性问题。
  • 五是:异构平台的可移植性,hdfs在设计的时候就考虑到平台的可移植性,这种特性方便了hdfs作为大规模数据应用平台的推广。

HDFS数据处理

HDFS存储原理:冗余数据保存

作为一个分布式文件系统,为了保证系统的容错性和可用性,HDFS采用了多副本方式对数据进行冗余存储,通常一个数据块的多个副本会被分布到不同的数据节点上,如图所示,数据块1被分别存放到数据节点AC上,数据块2被存放在数据节点AB上。

优点:(1加快数据传输速度(2容易检查数据错误(3保证数据可靠性

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第9张图片 HDFS数据块多副本存储

数据存放规则:

  • 第一个副本:放置在上传文件的数据节点;如果是集群外提交,则随机挑选一台磁盘不太满、CPU不太忙的节点
  • 第二个副本:放置在与第一个副本不同的机架的节点上
  • 第三个副本:与第一个副本相同机架的其他节点上
  • 更多副本:随机节点
Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第10张图片 Block的副本放置策略

HDFS存储原理:数据读取

获取机架ID:HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端也可以调用API获取自己所属的机架ID。当客户端读取数据时,从名称节点获得数据块不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属的机架ID,当发现某个数据块副本对应的机架ID和客户端对应的机架ID相同时,就优先选择该副本读取数据,如果没有发现,就随机选择一个副本读取数据。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第11张图片

数据错误与恢复

HDFS具有较高的容错性,可以兼容廉价的硬件,它把硬件出错看作一种常态,而不是异常,并设计了相应的机制检测数据错误和进行自动恢复,主要包括以下几种情形:名称节点出错、数据节点出错和数据出错

名称节点出错

名称节点保存了所有的元数据信息,其中,最核心的两大数据结构是FsImageEditlog,如果这两个文件发生损坏,那么整个HDFS实例将失效。因此,HDFS设置了备份机制,把这些核心文件同步复制到备份服务器SecondaryNameNode。当名称节点出错时,就可以根据备份服务器SecondaryNameNode中的FsImageEditlog数据进行恢复。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第12张图片

数据节点出错

每个数据节点会定期向名称节点发送“心跳”信息,向名称节点报告自己的状态。当数据节点发生故障,或者网络发生断网时,名称节点就无法收到来自一些数据节点的心跳信息,这时,这些数据节点就会被标记为“宕机”,节点上面的所有数据都会被标记为“不可读”,名称节点不会再给它们发送任何I/O请求。

这时,有可能出现一种情形,即由于一些数据节点的不可用,会导致一些数据块的副本数量小于冗余因子,名称节点会定期检查这种情况,一旦发现某个数据块的副本数量小于冗余因子,就会启动数据冗余复制,为它生成新的副本。

HDFS和其它分布式文件系统的最大区别就是可以调整冗余数据的位置。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第13张图片

网络传输和磁盘错误等因素,都会造成数据错误。客户端在读取到数据后,会采用md5sha1对数据块进行校验,以确定读取到正确的数据。

在文件被创建时,客户端就会对每一个文件块进行信息摘录,并把这些信息写入到同一个路径的隐藏文件里面。当客户端读取文件的时候,会先读取该信息文件,然后,利用该信息文件对每个读取的数据块进行校验,如果校验出错,客户端就会请求到另外一个数据节点读取该文件块,并且向名称节点报告这个文件块有错误,名称节点会定期检查并且重新复制这个块。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第14张图片

HDFS数据读写过程

  • FileSystem是一个通用文件系统的抽象基类,可以被分布式文件系统继承,所有可能使用Hadoop文件系统的代码,都要使用这个类
  • HadoopFileSystem这个抽象类提供了多种具体实现
  • DistributedFileSystem就是FileSystemHDFS文件系统中的具体实现
  • FileSystemopen()方法返回的是一个输入流FSDataInputStream对象,在HDFS文件系统中,具体的输入流就是DFSInputStreamFileSystem中的create()方法返回的是一个输出流FSDataOutputStream对象,在HDFS文件系统中,具体的输出流就是DFSOutputStream
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
FSDataInputStream in = fs.open(new Path(uri));
FSDataOutputStream out = fs.create(new Path(uri));

注意:创建一个Configuration对象时,其构造方法会默认加载工程项目下两个配置文件,分别是hdfs-site.xml以及core-site.xml,这两个文件中会有访问HDFS所需的参数值,主要是fs.defaultFS,指定了HDFS的地址(比如hdfs://localhost:9000),有了这个地址客户端就可以通过这个地址访问HDFS了。

HDFS读数据的过程

1.首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例。

2.DistributedFileSystem通过rpc获得文件的第一批block的locations,同一个block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。

3.前两步会返回一个FSDataInputStream对象,该对象会被封装DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。

4.数据从datanode源源不断的流向客户端。

5.如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。

6.如果第一批block都读完了, DFSInputStream就会去namenode拿下一批block的locations,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。

如果在读数据的时候, DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排序第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。 DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像。

该设计就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode, namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第15张图片

import java.io.BufferedReader;
import java.io.InputStreamReader;
 
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FSDataInputStream;
 
public class Chapter3 {    
    public static void main(String[] args) {
        try {
            Configuration conf = new Configuration();  
            FileSystem fs = FileSystem.get(conf);
            Path filename = new Path(“hdfs://localhost:9000/user/hadoop/test.txt");
            FSDataInputStream is = fs.open(filename);            
            BufferedReader d = new BufferedReader(new InputStreamReader(is));
            String content = d.readLine(); //读取文件一行 
            System.out.println(content);
            d.close(); //关闭文件 
            fs.close(); //关闭hdfs 
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第16张图片

HDFS写数据的过程

1.客户端通过调用DistributedFileSystem的create方法创建新文件。

2.DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前, namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过, namenode就会记录下新文件,否则就会抛出IO异常。

3.前两步结束后,会返回FSDataOutputStream的对象,与读文件的时候相似, FSDataOutputStream被封装成DFSOutputStream。DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小的packet,然后排成队列data quene。

4.DataStreamer会去处理接受data quene,它先询问namenode这个新的block最适合存储的在哪几个datanode里(比如重复数是3,那么就找到3个最适合的datanode),把他们排成一个pipeline。DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。

5.DFSOutputStream还有一个对列叫ack quene,也是由packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时akc quene才会把对应的packet包移除掉。

如果在写的过程中某个datanode发生错误,会采取以下几步:

1) pipeline被关闭掉;

2)为了防止丢包ack quene里的packet会同步到data quene里;

3)把产生错误的datanode上当前在写但未完成的block删掉;

4)block剩下的部分被写到剩下的两个正常的datanode中;

5)namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。

6.客户端完成写数据后调用close方法关闭写入流。

7.DataStreamer把剩余得包都刷到pipeline里,然后等待ack信息,收到最后一个ack后,通知datanode把文件标视为已完成。

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第17张图片

import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.Path;
 
public class Chapter3 {    
    public static void main(String[] args) { 
        try {
            Configuration conf = new Configuration();  
            FileSystem fs = FileSystem.get(conf);
            byte[] buff = "Hello world".getBytes(); // 要写入的内容 
            String filename = " hdfs://localhost:9000/user/hadoop/test.txt "; //要写入的文件名 
            FSDataOutputStream os = fs.create(new Path(filename));
            os.write(buff,0,buff.length);
            System.out.println("Create:"+ filename); 
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API)_第18张图片

Hadoop Shell基本操作

调用文件系统(FS)Shell命令应使用 hadoop fs 的形式。 所有的的FS shell命令使用URI路径作为参数。URI格式是scheme://authority/path。对HDFS文件系统,scheme是hdfs,对本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme。一个HDFS文件或目录比如/parent/child可以表示成hdfs://namenode:namenodeport/parent/child,或者更简单的/parent/child(假设你配置文件中的默认值是namenode:namenodeport)。大多数FS Shell命令的行为和对应的Unix Shell命令类似,出错信息会输出到stderr,其他信息输出到stdout。

1.打开终端模拟器,切换到/apps/hadoop/sbin目录下,启动Hadoop

  1. cd /apps/hadoop/sbin  
  2. ./start-all.sh  

除了直接执行start-all.sh外,还可以分步启动start-dfs.sh和start-yarn.sh。

2.执行jps,检查一下Hadoop相关进程是否启动

  1. jps  

3.在/目录下创建一个test1文件夹

  1. hadoop fs -mkdir /test1  

4.在Hadoop中的test1文件夹中创建一个file.txt文件

  1. hadoop fs -touchz /test1/file.txt  

5.查看根目录下所有文件

  1. hadoop fs -ls /  

6.还可以使用ls -R的方式递归查看根下所有文件

  1. hadoop fs -ls -R /  

7.将Hadoop根下test1目录中的file.txt文件,移动到根下并重命名为file2.txt

  1. hadoop fs -mv /test1/file.txt /file2.txt  

Hadoop中的mv用法同Linux中的一样,都可以起到移动文件和重命名的作用。

8.将Hadoop根下的file2.txt文件复制到test1目录下

  1. hadoop fs -cp /file2.txt /test1  

9.在Linux本地/data目录下,创建一个data.txt文件,并向其中写入hello hadoop!

  1. cd /data  
  2. touch data.txt  
  3. echo hello hadoop! >> data.txt  

10.将Linux本地/data目录下的data.txt文件,上传到HDFS中的/test1目录下

  1. hadoop fs -put /data/data.txt /test1  

11.查看Hadoop中/test1目录下的data.txt文件

  1. hadoop fs -cat /test1/data.txt  

12.除此之外还可以使用tail方法

  1. hadoop fs -tail /test1/data.txt  

tail方法是将文件尾部1K字节的内容输出。支持-f选项,行为和Unix中一致。

13.查看Hadoop中/test1目录下的data.txt文件大小

  1. hadoop fs -du -s /test1/data.txt  

-du 后面可以不加-s,直接写目录表示查看该目录下所有文件大小

14.text方法可以将源文件输出为文本格式。允许的格式是zip和TextRecordInputStream。

  1. hadoop fs -text /test1/data.txt  

15.stat方法可以返回指定路径的统计信息,有多个参数可选,当使用-stat选项但不指定format时候,只打印文件创建日期,相当于%y

  1. hadoop fs -stat /test1/data.txt  

下面列出了format的形式:

  • %b:打印文件大小(目录为0)
  • %n:打印文件名
  • %o:打印block size (我们要的值)
  • %r:打印备份数
  • %y:打印UTC日期 yyyy-MM-dd HH:mm:ss
  • %Y:打印自1970年1月1日以来的UTC微秒数
  • %F:目录打印directory, 文件打印regular file

16.将Hadoop中/test1目录下的data.txt文件,下载到Linux本地/apps目录中

  1. hadoop fs -get /test1/data.txt /apps  

17.查看一下/apps目录下是否存在data.txt文件

  1. ls /apps  

18.使用chown方法,改变Hadoop中/test1目录中的data.txt文件拥有者为root,使用-R将使改变在目录结构下递归进行。

  1. hadoop fs -chown root /test1/data.txt  

19.使用chmod方法,赋予Hadoop中/test1目录中的data.txt文件777权限

  1. hadoop fs -chmod 777 /test1/data.txt  

20.删除Hadoop根下的file2.txt文件

  1. hadoop fs -rm /file2.txt  

21.删除Hadoop根下的test1目录

  1. hadoop fs -rm -r /test1  

22.当在Hadoop中设置了回收站功能时,删除的文件会保留在回收站中,可以使用expunge方法清空回收站。

  1. hadoop fs -expunge  

在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块。运行期通过命令也可以进入安全模式。在实践过程中,系统启动的时候去修改和删除文件也会有安全模式不允许修改的出错提示,只需要等待一会儿即可。

23.使用Shell命令执行Hadoop自带的WordCount

首先切换到/data目录下,使用vim编辑一个data.txt文件,内容为(hello world hello hadoop hello ipieuvre)

  1. cd /data  
  2. vim data.txt  

在HDFS的根下创建in目录,并将/data下的data.txt文件上传到HDFS中的in目录

  1. hadoop fs -put /data/data.txt /in  

执行hadoop jar命令,在hadoop的/apps/hadoop/share/hadoop/mapreduce路径下存在hadoop-mapreduce-examples-2.6.0-cdh5.4.5.jar包,我们执行其中的worldcount类,数据来源为HDFS的/in目录,数据输出到HDFS的/out目录

  1. hadoop jar /apps/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.4.5.jar wordcount /in /out  

查看HDFS中的/out目录

  1. hadoop fs -ls /out  
  2. hadoop fs -cat /out/*  

24.进入Hadoop安全模式

  1. hdfs dfsadmin -safemode enter  

25.退出Hadoop安全模式

view plain copy

  1. hdfs dfsadmin -safemode leave  

26.切换到/apps/hadoop/sbin目录下,关闭Hadoop

view plain copy

  1. cd /apps/hadoop/sbin  
  2. ./stop-all.sh  

HDFS Java API

HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础篇,为了实现本地与HDFS的文件传输,主要借助Eclipse开发环境,通过java编程实现了远程HDFS的文件创建,上传,下载,删除等。

其实对HDSF的文件操作主要有两种方式:命令行的方式和JavaAPI的方式。命令行的方式简单直接,但是必须要求本地机器也是在Linux系统中已经安装了hadoop,这对习惯用windows系统的用户来说不得不安装虚拟机,然后再在虚拟机上安装Linux系统,这是一种挑战。同时windows系统与虚拟机上安装的Linux系统进行文件传输也是要借助一些工具才可以实现。

为了实现以上所遇到诸如系统不一致,手动输入命令等的困扰,我们选择Java API的方式,有专门的API函数,可以在非Hadoop机器上实现访问,同时与系统无关(windows、Linux甚至XP系统也可以)。Hadoop中关于文件操作类基本上全部是在"org.apache.hadoop.fs"包中,Hadoop类库中最终面向用户提供的接口类是FileSystem,该类封装了几乎所有的文件操作,例如CopyToLocalFile、CopyFromLocalFile、mkdir及delete等。综上基本上可以得出操作文件的程序库框架:

operator( ) {

    得到Configuration对象

    得到FileSystem对象

    进行文件操作

}

实现上述程序库框架中各个操作的具体步骤:

Java抽象类org.apache.hadoop.fs.FileSystem定义了hadoop的一个文件系统接口。该类是一个抽象类,通过以下两种静态工厂方法可以过去FileSystem实例:

public static FileSystem.get(Configuration conf) throws IOException

public static FileSystem.get(URI uri, Configuration conf) throws IOException

HDFS上的文件创建,上传,下载,删除等操作的具体方法实现:

(1)public boolean mkdirs(Path f) throws IOException

一次性新建所有目录(包括父目录), f是完整的目录路径。

(2)public FSOutputStream create(Path f) throws IOException

创建指定path对象的一个文件,返回一个用于写入数据的输出流

create()有多个重载版本,允许我们指定是否强制覆盖已有的文件、文件备份数量、写入文件缓冲区大小、文件块大小以及文件权限。

(3)public boolean copyFromLocal(Path src, Path dst) throws IOException

将本地文件拷贝到文件系统

(4)public boolean exists(Path f) throws IOException

检查文件或目录是否存在

(5)public boolean delete(Path f, Boolean recursive)

永久性删除指定的文件或目录,如果f是一个空目录或者文件,那么recursive的值就会被忽略。只有recursive=true时,一个非空目录及其内容才会被删除。

(6)FileStatus类封装了文件系统中文件和目录的元数据,包括文件长度、块大小、备份、修改时间、所有者以及权限信息。

本实验涉及到使用Java API对HDFS的一些基本操作。

  1. 创建类MakeDir.class,在HDFS的根目录下,创建名为hdfstest的目录。
  2. 创建类TouchFile.class,在HDFS的目录/hdfstest下,创建名为touchfile的文件。
  3. 创建类CopyFromLocalFile.class,将linux本地文件/data/mydata/sample_data,上传到HDFS文件系统的/hdfstest目录下。
  4. 创建类CopyToLocalFile.class,将HDFS文件系统上的文件/hdfstest/sample_data,下载到本地/data/mydata/copytolocal 。
  5. 创建类ListFiles.class,列出HDFS文件系统/hdfstest目录下,所有的文件,以及文件的权限、用户组、所属用户。
  6. 创建类IteratorListFiles.class,列出HDFS文件系统/根目录下,以及各级子目录下,所有文件以及文件的权限、用户组,所属用户。
  7. 了解FileSystem类下的方法,例如:判断文件是否存在、删除文件、重命名文件等。
  8. 创建类LocateFile.class,查看HDFS文件系统上,文件/hdfstest/sample_data的文件块信息。
  9. 创建类WriteFile.class,在HDFS上,创建/hdfstest/writefile文件,并在文件中写入内容“hello world hello data!”。
  10. 创建类PutMerge.class,将Linux本地文件夹/data/mydata/下的所有文件,上传到HDFS上并合并成一个文件/hdfstest/mergefile。

1.切换目录到/apps/hadoop/sbin下,启动hadoop。

view plain copy

  1. cd /apps/hadoop/sbin  
  2. ./start-all.sh  

在Linux本地创建/data/hadoop4目录。

view plain copy

  1. mkdir -p /data/hadoop4  

2.切换到/data/hadoop4目录,用wget命令,从http://59.64.78.41:60000/allfiles/hadoop4/网址上下载依赖包hadoop2lib.tar.gz,并解压到当前目录。

view plain copy

  1. cd /data/hadoop4  
  2. wget http://59.64.78.41:60000/allfiles/hadoop4/hadoop2lib.tar.gz  
  3. tar zxvf hadoop2lib.tar.gz  

3.新建JAVA项目,名为hadoop4。

4.在hadoop4项目下新建包,名为my.hdfs。

5.在hadoop4项目下创建目录,名为hadoop4lib,用于存放项目所需依赖包。

6.从/data/hadoop4/hadoop2lib目录下拷贝所有jar包到项目下的hadoop4lib目录。选中hadoop4lib里面的所有jar包,右键点击BuildPath=>Add to Build Path选项。

7.在my.hdfs包下,新建类MakeDir,程序功能是在HDFS的根目录下,创建名为hdfstest的目录。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class MakeDir {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration conf = new Configuration();  
  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);  
  
        String newDir = "/hdfstest";  
  
        boolean result = hdfs.mkdirs(new Path(newDir));  
        if (result) {  
            System.out.println("Success!");  
        }else {  
            System.out.println("Failed!");  
        }  
    }  
}  

在Eclipse里执行,然后在HDFS上查看实验结果。

hadoop fs -ls / 

8.在my.hdfs包下,新建类TouchFile,程序功能是在HDFS的目录/hdfstest下,创建名为touchfile的文件。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FSDataOutputStream;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class TouchFile {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration configuration = new Configuration();  
  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(new URI(hdfsPath), configuration);  
  
        String filePath = "/hdfstest/touchfile";  
  
        FSDataOutputStream create = hdfs.create(new Path(filePath));  
  
        System.out.println("Finish!");  
    }  
}  

在Eclipse里执行,然后在hdfs上查看实验结果。

hadoop fs -lsr / 

9.在/data/hadoop4下使用vim打开sample_data文件,向sample_data文件中写入hello world。(使用vim编辑时,需输入a,开启输入模式)

cd /data/hadoop4  
vim sample_data  

hello world

在my.hdfs包下,创建类CopyFromLocalFile.class,程序功能是将本地linux操作系统上的文件/data/hadoop4/sample_data,上传到HDFS文件系统的/hdfstest目录下。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class CopyFromLocalFile {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration conf = new Configuration();  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);  
        String from_Linux = "/data/hadoop4/sample_data";  
        String to_HDFS = "/hdfstest/";  
        hdfs.copyFromLocalFile(new Path(from_Linux), new Path(to_HDFS));  
        System.out.println("Finish!");  
    }  
}  

在Eclipse里执行,然后在HDFS上查看实验结果。

hadoop fs -lsr  /

10.在/data/hadoop4/下创建目录copytolocal。

mkdir /data/hadoop4/copytolocal

在my.hdfs包下,创建类CopyToLocalFile.class,程序功能是将HDFS文件系统上的文件/hdfstest/sample_data,下载到本地/data/hadoop4/copytolocal 。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class CopyToLocalFile {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration conf = new Configuration();  
  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);  
  
        String from_HDFS = "/hdfstest/sample_data";  
        String to_Linux = "/data/hadoop4/copytolocal";  
  
        hdfs.copyToLocalFile(false, new Path(from_HDFS), new Path(to_Linux));  
  
        System.out.println("Finish!");  
    }  
}  

在Eclipse里执行,然后在Linux本地/data/hadoop4上查看实验结果。

  1. cd /data/hadoop4/copytolocal  
  2. ls 

11.在my.hdfs包下,新建类ListFiles,程序功能是列出HDFS文件系统/hdfstest目录下,所有的文件,以及文件的权限、用户组、所属用户。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileStatus;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class ListFiles {  
    public static void main(String[] args) throws IOException {  
        Configuration conf = new Configuration();  
        String hdfspath = "hdfs://localhost:9000/";  
        FileSystem hdfs = FileSystem.get(URI.create(hdfspath), conf);  
        String watchHDFS = "/hdfstest";  
        FileStatus[] files = hdfs.listStatus(new Path(watchHDFS));  
        for (FileStatus file : files) {  
            System.out.println(file.getPermission() + " " + file.getOwner()  
                    + " " + file.getGroup() + " " + file.getPath());  
        }  
    }  
}  

在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。

12.在my.hdfs包下,新建类IteratorListFiles,程序功能是列出HDFS文件系统/根目录下,以及各级子目录下,所有文件以及文件的权限、用户组,所属用户。

package my.hdfs;  
import java.io.FileNotFoundException;  
import java.io.IOException;  
import java.net.URI;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FileStatus;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class IteratorListFiles {  
    public static void main(String[] args) throws IOException {  
        Configuration conf = new Configuration();  
        String hdfspath = "hdfs://localhost:9000/";  
        FileSystem hdfs = FileSystem.get(URI.create(hdfspath), conf);  
        String watchHDFS = "/";  
  
        iteratorListFile(hdfs, new Path(watchHDFS));  
    }  
    public static void iteratorListFile(FileSystem hdfs, Path path)  
            throws FileNotFoundException, IOException {  
        FileStatus[] files = hdfs.listStatus(path);  
        for (FileStatus file : files) {  
            if (file.isDirectory()) {  
                System.out.println(file.getPermission() + " " + file.getOwner()  
                        + " " + file.getGroup() + " " + file.getPath());  
                iteratorListFile(hdfs, file.getPath());  
            } else if (file.isFile()) {  
                System.out.println(file.getPermission() + " " + file.getOwner()  
                        + " " + file.getGroup() + " " + file.getPath());  
            }  
        }  
    }  
} 

在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。

13.文件是否存在、删除文件、重命名文件

了解FileSystem类下的方法,例如:判断文件是否存在、删除文件、重命名文件等。

FileSystem的方法exists、delete、rename。

14.在my.hdfs包下,新建类LocateFile,程序功能是查看HDFS文件系统上,文件/hdfstest/sample_data的文件块信息。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.BlockLocation;  
import org.apache.hadoop.fs.FileStatus;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class LocateFile {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration conf = new Configuration();  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(new URI(hdfsPath), conf);  
  
        Path file = new Path("/hdfstest/sample_data");  
        FileStatus fileStatus = hdfs.getFileStatus(file);  
  
        BlockLocation[] location = hdfs.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());  
        for (BlockLocation block : location) {  
            String[] hosts = block.getHosts();  
            for (String host : hosts) {  
                System.out.println("block:" +block + " host:"+ host);  
            }  
        }  
    }  
}  

在Eclipse里执行,然后在Eclipse的控制界面Console上查看实验结果。

15.在my.hdfs包下,新建类WriteFile,程序功能是在HDFS上,创建/hdfstest/writefile文件并在文件中写入内容“hello world hello data!”。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FSDataOutputStream;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class WriteFile {  
    public static void main(String[] args) throws IOException {  
        Configuration conf = new Configuration();  
  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs = FileSystem.get(URI.create(hdfsPath), conf);  
  
        String filePath = "/hdfstest/writefile";  
  
        FSDataOutputStream create = hdfs.create(new Path(filePath));  
  
        System.out.println("Step 1 Finish!");  
  
        String sayHi = "hello world hello data!";  
        byte[] buff = sayHi.getBytes();  
        create.write(buff, 0, buff.length);  
        create.close();  
        System.out.println("Step 2 Finish!");  
    }  
}  

在Eclipse里执行,然后在HDFS上查看实验结果。

hadoop fs -lsr /hdfstest  
hadoop fs -cat /hdfstest/writefile 

16.首先切换到/data/hadoop4目录下,将该目录下的所有文件删除(此时要求/data/hadoop4中必须全是文件,不能有目录)。然后在该目录下新建两文件,分别命名为file1 ,file2。向file1和file2中,分别输入内容。

cd /data/hadoop4  
rm -r /data/hadoop4/* 

touch file1  
touch file2  

echo "hello file1" > file1  
echo "hello file2" > file2  

在my.hdfs包下,新建类PutMerge,程序功能是将Linux本地文件夹/data/hadoop4/下的所有文件,上传到HDFS上并合并成一个文件/hdfstest/mergefile。

package my.hdfs;  
import java.io.IOException;  
import java.net.URI;  
import java.net.URISyntaxException;  
import org.apache.hadoop.conf.Configuration;  
import org.apache.hadoop.fs.FSDataInputStream;  
import org.apache.hadoop.fs.FSDataOutputStream;  
import org.apache.hadoop.fs.FileStatus;  
import org.apache.hadoop.fs.FileSystem;  
import org.apache.hadoop.fs.Path;  
public class PutMerge {  
    public static void main(String[] args) throws IOException, URISyntaxException {  
        Configuration conf = new Configuration();  
        String hdfsPath = "hdfs://localhost:9000";  
        FileSystem hdfs  = FileSystem.get(new URI(hdfsPath), conf);  
        FileSystem local = FileSystem.getLocal(conf);  
        String from_LinuxDir = "/data/hadoop4/";  
        String to_HDFS = "/hdfstest/mergefile";  
        FileStatus[] inputFiles = local.listStatus(new Path(from_LinuxDir));  
        FSDataOutputStream out = hdfs.create(new Path(to_HDFS));  
  
        for (FileStatus file : inputFiles) {  
            FSDataInputStream in = local.open(file.getPath());  
            byte[] buffer = new byte[256];  
            int bytesRead = 0;  
            while ( (bytesRead = in.read(buffer) ) > 0) {  
                out.write(buffer, 0, bytesRead);  
            }  
            in.close();  
        }  
        System.out.println("Finish!");  
    }  
}  

在Eclipse里执行,然后在HDFS上查看实验结果。

hadoop fs -ls /hdfstest 

 

你可能感兴趣的:(Hadoop - HDFS(体系结构介绍、HDFS数据处理、Hadoop Shell基本操作、HDFS Java API))