Hadoop分布式文件系统HDFS入门

HDFS

HDFS(Hadoop Distributed File System)Hadoop分布式文件系统

一、HDFS特性

  • 文件系统,存储文件,通过统一的命名空间目录树来定位文件;
  • 分布式,由很多服务器联合起来实现其功能。
  1. master/slave架构

一般一个 HDFS 集群是有一个 Namenode 和一定数目的Datanode 组成。Namenode 是 HDFS 集群主节点,Datanode 是 HDFS 集群从节点,两种角色各司其职,共同协调完成分布式的文件存储服务。

  1. 分块存储

HDFS 中的文件在物理上是分块存储(block)的,块的大小可以通过配置参数来规定,默认大小在 hadoop2.x 版本中是 128M。

  1. 名字空间

用户或者应用程序可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。

  1. Namenode元数据管理

Namenode 负责维护整个hdfs文件系统的目录树结构,以及每一个文件所对应的 block 块信息(block 的id,及所在的datanode 服务器)。

  1. Datanode数据存储

文件的各个 block 的具体存储管理由 datanode 节点承担。每一个 block 都可以在多个datanode 上。Datanode 需要定时向 Namenode 汇报自己持有的 block信息。 存储多个副本(副本数量也可以通过参数设置 dfs.replication,默认是 3)

  1. 副本机制

为了容错,文件的所有 block 都会有副本。每个文件的 block 大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可以在之后改变。

  1. 一次写入,多次读出

频繁的写入会造成元数据的频繁的更新改变,比较麻烦。
正因为如此,HDFS 适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。


二、HDFS命令

1、常用的操作命令

#查看根路径下面的文件或者文件夹
hdfs  dfs  -ls  /  

#在hdfs上面递归的创建文件夹
hdfs  dfs  -mkdir  -p  /xx/xxx  

#从本地移动到hdfs
hdfs  dfs -moveFromLocal  sourceDir(本地磁盘的文件或者文件夹的路径)   destDir(hdfs的路径)  

#移动 (hdfs上的移动)
hdfs  dfs  -mv  hdfsSourceDir   hdfsDestDir

#将本地文件系统的文件或者文件夹放到hdfs上面去
hdfs  dfs -put  localDir  hdfsDir  

#查看hdfs的文件内容
hdfs  dfs -cat  hdfsDir 

#拷贝文件或者文件夹
hdfs  dfs  -cp  hdfsSourceDIr   hdfsDestDi

#(递归)删除文件或者文件夹
hdfs  dfs  -rm   [-r]  

#hdfs的权限管理两个命令:
hdfs  dfs  -chmod -R  777  /xxx
hdfs  dfs  -chown  -R hadoop:hadoop  /xxx

2、高级命令


安全模式

hadoop的安全模式:hadoop集群刚启动的时候,默认处于安全模式30秒,安全模式的时候对外不提供给任何服务
刚开始启动的时候,处于安全模式:检测我们的datanode去了

基准测试

  • 测试写入速度
hadoop jar /export/servers/hadoop-2.6.0-cdh5.14.0/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.0-cdh5.14.0.jar TestDFSIO  -write -nrFiles 10 -fileSize 10MB

写入速度一般在30M/S左右超不多

  • 测试读取速度
hadoop jar /export/servers/hadoop-2.6.0-cdh5.14.0/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.0-cdh5.14.0.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB
一般通过MR读取速度大概在100M/s左右

三、一些概念

  1. 一台满了,需加多几台,数据究竟存在哪些机器上? 元数据记录(一条元数据信息大概150字节)
  2. 上传一个比任何一台服务器的磁盘都要大的文件?切块(小文件也需要切块,好存且要计算)
  3. 如何解决块丢失问题?副本机制

1、分布式文件计算系统

文件系统是一个抽象类,里面有很多的子实现类,例如 hdfs,file:///, ftp文件系统 , webHdfs

把磁盘的真实存放抽象成目录结构给用户看 这就是文件系统(FileSystem)干的

小文件占元数据信息和block,占线程占资源————>合并

2、HDFS的架构图

主从架构

主节点与从节点存在 心跳机制 负载均衡 副本机制

3、副本机制以及block块缓存

hdfs-site.xml
dfs.blocksize
实际中一般比128大
根据CPU 内存 性能设置

  • block块缓存:可以将我们的block块缓存到内存当中,我们在执行一些MR计算的时候,可以直接从内存当中获取数据,比较快,特别适用于一些小表join大表的情况
  • hdfs的权限验证:采用的是linux类似的权限校验机制,防止好人做错事,不能阻止坏人干干事,hdfs相信你告诉我你是谁,你就是谁

4、hdfs元数据信息fsimage与edits

在hdfs-site.xml当中的配置

dfs.namenode.name.dir:fsimage文件存储的路径
dfs.namenode.edits.dir:edits文件存储的路径

fsimage:(某时间前的元数据信息)namenode中元数据在内存,但要持久化保存在硬盘。————负责开机后加载加载元数据到内存

edits:对元数据操作的日志记录(一段时间)

SencondaryNamenode:复制fsimage + 剪切edits(把以前的edits清空),合并=fsimage.ctp,赶紧覆盖fsimage————复制合并日志

SecondaryNameNode如何辅助namenode管理元数据信息
主要的作用就是合并fsimage与edits
edist出发合并的两个条件,如:

  • 条件一 edits文件达到64M
  • 条件二 一个小时合并一次

5、hdfs的文件读写过程

hdfs的文件写入过程:

  • 第一步:客户端发出请求,请求namneode需要上传数据
  • 第二步:namenode检测客户端是或否有权限上传
  • 第三步:客户端请求namenode第一个block块上传到哪里去
  • 第四步:namenode找n个block块返回给客户端
  • 第五步:客户端找datanode建立pipeline管道,主备上传数据,数据都是以packet包的形式通过管道上传到datanode上面去
  • 第六步:datanode保存好了之后,给客户端一个ack确认机制,客户端准备上传下一个block块,直到所有的block块上传完成,关闭文件流。

一个packet 64k

读取过程:

  1. Client向NameNode发出读取请求
  2. NameNode检测客户端是否有权限读取以及需要读取的文件是否存在(NameNode告诉客户端允许读取数据,NameNode查找元数据信息,告诉客户端block块存储在哪里)
  3. 客户端获取到block块地址之后,与datanade通信,通过pipeline管道进行数据的传输
  4. 客户端读取完所有的block块,然后再客户端本地拼接成一个完整的文件

四、hdfs的JavaAPI

1、使用文件系统方式访问数据

    public void getFileSystem() throws Exception {

        //如果configuration 不做任何配置,获取到的是本地文件系统
        Configuration configuration = new Configuration();
        configuration.set("fs.defaultFS", "hdfs://node01:8020/");
        FileSystem fileSystem = FileSystem.get(configuration);
        System.out.println(fileSystem.toString());
    }

2、递归遍历文件系统当中的所有文件

/**
 * 递归遍历hdfs当中所有的文件路径
 */
@Test
public void getAllHdfsFilePath() throws Exception {
    //获取分布式文件系统的客户端
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

    //给定我们hdfs的根路径
    Path path = new Path("/");

    getDirectoryFile(fileSystem,path);

    fileSystem.close();

}

/**
 * 遍历文件路径
 */
private void getDirectoryFile(FileSystem fileSystem, Path path) throws Exception {
    //获取path路径下所有的文件详情列表
    FileStatus[] fileStatuses = fileSystem.listStatus(path);

    //遍历详情列表
    for (FileStatus fileStatus : fileStatuses) {

        //如果是文件夹,则递归调用自己
        if (fileStatus.isDirectory()) {
            getDirectoryFile(fileSystem, fileStatus.getPath());
        } else {
            //如果是文件,则直接输出文件的绝对路径
            System.out.println(fileStatus.getPath());
        }
    }
}

3、下载文件到本地

/**
 * 下载hdfs文件到本地
 */
@Test
public void copyHdfsToLocal()throws  Exception{
    //获取分布式文件系统的客户端
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

    //给定hdfs文件的路径
    Path path = new Path("/test/input/install.log");
    //使用一个输入流去读取hdfs的文件
    FSDataInputStream inputStream = fileSystem.open(path);

    //输出流,将我们的数据输出到本地路径下面去
    FileOutputStream outputStream = new FileOutputStream(new File("c:\\myinstall.log"));

    IOUtils.copy(inputStream,outputStream);
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);

    //通过copyToLocalFile来将hdfs的文件下载到本地
   // fileSystem.copyToLocalFile(new Path("hdfs://node01:8020/test/input/install.log"),new Path("file:///c:\\myinstall2.log"));

    fileSystem.close();

}

4、hdfs上创建文件夹

/**
 * hdfs上面创建文件夹
 */
@Test
public void createHdfsDir() throws  Exception{
    //获取分布式文件系统的客户端对象
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

    fileSystem.mkdirs(new Path("/abc/bbc/ddd"));

    fileSystem.close();

}

5、hdfs文件上传

/**
 * hdfs的文件上传
 */
@Test
public void uploadFileToHdfs() throws Exception {

    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());

    fileSystem.copyFromLocalFile(false, new Path("file:///d:\\lala.txt"), new Path("/abc/bbb/ccc"));

    fileSystem.close();
}

6、权限问题以及伪造用户

/**
 * hafs的权限校验机制
 */
@Test
public void hdfsPermission() throws Exception {

    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(), "root");

    fileSystem.copyToLocalFile(new Path("hdfs://node01:8020/test/input/install.log"), new Path("file:///d:\\core-site.xml"));

    fileSystem.close();

}

7、小文件合并

 /**
 * hdfs在上传小文件的时候进行合并
 */

@Test
public void mergeFile()throws  Exception{

    //在hdf上面创建一个文件

    //获取本地文件,上传到hdfs创建的文件里面去
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(), "root");
    FSDataOutputStream fsDataOutputStream = fileSystem.create(new Path("/bigfile.xml"));

    //获取本地所有小文件的输入流
    //首先获取本地文件系统
    LocalFileSystem localFileSystem = FileSystem.getLocal(new Configuration());
    FileStatus[] fileStatuses = localFileSystem.listStatus(new Path("file:///F:\\上传小文件合并"));
    for (FileStatus fileStatus : fileStatuses) {
        Path path = fileStatus.getPath();
        FSDataInputStream inputStream = localFileSystem.open(path);
        IOUtils.copy(inputStream,fsDataOutputStream);
        //通过拷贝,将我们的本地文件上传到hdfs上面去
        IOUtils.closeQuietly(inputStream);
    }
    //关闭输出流
    IOUtils.closeQuietly(fsDataOutputStream);
    //关闭客户端
    fileSystem.close();
    localFileSystem.close();

}
  • 方案一:从源头解决

  • 方案二:sequenceFile

  • 方案三:har归档文件

从hdfs下载文件到本地(类似网盘下载)

public class DownFile {
    @Test
    public void downAllHdfsFile() throws URISyntaxException, IOException {
        FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://node01:8020"), new Configuration());
        Path path = new Path("/abc");
        File file = new File("F:\\hdfs\\" + path.getName());
        if (!file.exists()) {
            file.mkdirs();
        }
        downHdfsDirectory(file, fileSystem, path);
        fileSystem.close();
    }

    private void downHdfsDirectory(File file, FileSystem fileSystem, Path path) throws IOException {

        //获取path路径下所有的文件详情列表
        FileStatus[] fileStatuses = fileSystem.listStatus(path);

        //遍历详情列表
        for (FileStatus fileStatus : fileStatuses) {
            //如果是文件夹,则递归调用自己
            if (fileStatus.isDirectory()) {
                File file1 = new File(file, fileStatus.getPath().getName());
                file1.mkdirs();
                downHdfsDirectory(file1, fileSystem, fileStatus.getPath());
            } else {
                Path path1 = fileStatus.getPath();
                FSDataInputStream inputStream = fileSystem.open(path1);
                FileOutputStream outputStream = new FileOutputStream(new File(file, path1.getName()));
                IOUtils.copy(inputStream, outputStream);
                IOUtils.closeQuietly(outputStream);
                IOUtils.closeQuietly(inputStream);
            }
        }
    }
}

发布了18 篇原创文章 · 获赞 19 · 访问量 5347

猜你喜欢

转载自blog.csdn.net/weixin_44586883/article/details/100973874