Hadoop基础知识补充

251 阅读11分钟
  1. NameNode和DataNode的作用

  2. 什么是管理者-工作者模式

  3. Hadoop的两种容错机制

    1. 备份
    2. 辅助NameNode
  4. 命令行接口

    1. 两个属性的理解
    2. 文件访问权限,超级用户
  5. 从Hadoop URL读取数据

  6. FileSystem API读取数据的三种方式及不同

  7. 在文件中获取指定位置的数据

    1. FileSystem写入,读取数据的过程

      1. FileSystem写入过程
      2. FileSystem读取过程
  8. 在运行jar包时,命令行参数是如何导入

  9. 文件模式匹配

1.NameNode和DataNode的作用

1.Nameode

1.1Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问

1.2维护着文件系统树和整棵树内所有的文件和目录,这些信息以两个文件的形式永久的存放在本地磁盘上:命名空间镜像和编辑日志文件

Snipaste_2023-10-09_16-11-44.png

对应的分别为日志文件和临时文件

Snipaste_2023-10-09_16-15-07.png

在配置core-site.xml设置的便是临时文件存放的位置

在配置集群过程中,对从节点分发hadoop并配置好之后,需要删除对应的临时文件夹和日志夹的原因便是删除临时镜像文件,这么做的目的是删除文件系统的数据,便于启动进程时,是一个全新的文件系统

1.3namenode记录各个块所在的数据节点信息,但是不会永久保存块的位置信息,在系统启动过程中国有Datanode重建,而Datanode又由Namenode统一调度,Namenode的文件树的信息被保存到临时文件目录下

2.Datanode

Datanode节点的映射。Datanode负责处理文件系统客户端的读写请求。在Namenode的统一调度下进行数据块的创建、删除和复制,并定期向Namenode发送其所存储的块的列表

2.什么是管理者-工作者模式

HDFS集群的管理者-工作者模式是Namenode和Datanode之间的管理与实现

一个管理者(Namenode) 管理多个工作者(Datanode)

HDFS采用master/slave架构。一个HDFS集群是由一个Namenode和一定数目的Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点一个,负责管理它所在节点上的存储。

这是为什么当主结点出现错误,没有Namenode时,HDFS文件系统无法使用。在实践中,主结点出错的机率时比较大的,这便需要对namenode实现容错

3.Hadoop的两种容错机制

备份

将持久状态写入到本地磁盘(写入本地临时文件),写入一个远程挂载的网络文件系统

辅助NameNode

运行一个辅助Namenode(# Secondary NameNode),但是其不能作为Namenode,不能将其理解为第二个Namenode

作用是定期通过编辑日志合并并命名空间镜像,以防止编辑日志过大,一般位于另一台机器上,并会在namenode发生错误时启动

hadoop集群搭建及编程实践中的hdfs-site.xml中的

Snipaste_2023-10-07_15-12-01.png

这里的node01要更改为node02

4.命令行接口

4.1两个属性的理解

1.fs.default.name

在core-site.xml文件中,设置fs.default.name为hdfs:node01:9000

HDFS文件系统是由URL指定的,在配置文件中使用hdfs URL来配置HDFS为Hadoop的默认文件系统

HDFS的守护程序通过该属性来确定HDFS namenode的主机及端口,HDFS客户端可以通过该属性得知namenode在哪里运行进而连接到它

2.dfs.replication

在hdfs-site.xml文件中,设置dfs.replication为3

含义是指定文件系统块副本为3,HDFS会将块复制到3个datanode,根据hadoop集群搭建及编程实践可知hadoop集群规划中是有3个datanode的

默认为3,但是在伪分布式中,可以设置为1,因为此时只有一个datanode

当设置为3时,由于只有一个datanode,HDFS无法将块复制到3个datanode中,就会发出块副本不足的警告

超级用户是namenode进程的标识,对于超级用户,系统不会执行任何权限检查

4.2文件访问权限,超级用户

针对文件和目录,HDFS的权限模式和POSIX相似

一共提供三种权限模式:只读(r),写入(w),可执行(x)

读取文件或列出目录内容需要只读权限

写入一个文件或是在一个目录上新建及删除文件或目录,需要写入权限

对于文件而言,可执行权限可以忽略,因为不能再HDFS中执行文件,但在访问一个目录的子项时需要该权限

5.从Hadoop URL读取数据

要从HDFS文件系统中读取数据,最简单的是使用java.net.URL

import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
​
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
​
/**
 * @author prettyspider
 * @ClassName Main
 * @description: TODO
 * @date 2023/10/9 11:50
 * @Version V1.0
 */public class UrlCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
​
    public static void main(String[] args) {
        InputStream in = null;
        try {
            in=new URL(args[0]).openStream();
            IOUtils.copyBytes(in,System.out,4096,false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

源码

public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
    synchronized (streamHandlerLock) {
        if (factory != null) {
            throw new Error("factory already defined");
        }
        @SuppressWarnings("removal")
        // 获取系统安茜接口
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkSetFactory();
        }
        handlers.clear();
​
        // safe publication of URLStreamHandlerFactory with volatile write
        factory = fac;
    }
}

用URL识别Hadoop的hdfs URL还需要额外的工作,使用静态代码块的作用是设置URL工厂中已经有FsUrlStreamHandlerFactory()对象了,这个方法最多只能调用一次

由源码可知,在加锁的情况下,初始化时factory是null,会检查系统的安全接口,在最终会将传入的对象复制给类的成员变量factory,由于用到了锁,需要将其设置为静态

方法最多只能运行一次,在同一时间运行多个,就会抛出factory a异常lready define异常

打包后传输到虚拟机上,运行

Snipaste_2023-10-09_20-37-51.png

jar下载提取码:fb7y

6.FileSystem API读取数据的三种方式及不同

由5知,URLStreamHandlerFactory有时是不可能被应用的,因此可以使用FileSystem API来打开一个文件的输入流

获取FileSystem实例有以下几种静态方法

public static FileSystem get(Configuration conf) throws IOException
public statuc FileSystem get(URI url,Configuration conf) throws OPException
public static FileSystem get(URI url,Configuration conf,String user) thorws IOException

Configuration 对象封装了客户端或服务器的配置,通过设置配置文件读取路径来实现

三种方法的区别:

1.第一种方法返回的是默认文件系统

2.第二种方法通过给定的URI方案和权限来确定要使用的文件系统,如果给定的URI中没有指定的方案,则返回默认文件系统

3.作为给定用户来访问文件系统,对安全来说至关重要

实现FileSystem API获取文件信息

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
​
import java.io.IOException;
import java.net.URI;
​
/**
 * @author prettyspider
 * @ClassName FileSystemCat
 * @description: TODO
 * @date 2023/10/9 20:53
 * @Version V1.0
 */public class FileSystemCat {
    public static void main(String[] args) {
        String hdfsUri = args[0];
        String path = args[1];
        String user = args[2];
        Configuration conf = new Configuration();
        FSDataInputStream in = null;
        try {
            FileSystem fs = FileSystem.get(URI.create(hdfsUri), conf, user);
            in = fs.open(new Path(path));
            IOUtils.copyBytes(in, System.out, 4096, false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

jar包下载提取码:kb69

7.在文件中获取指定位置的数据

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
​
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
​
/**
 * @author prettyspider
 * @ClassName GetMessage
 * @description: TODO
 * @date 2023/10/9 21:11
 * @Version V1.0
 */public class GetMessage {
    public static void main(String[] args) throws Exception {
        FileSystem fs = FileSystem.get(new URI("hdfs://node01:9000"), new Configuration(), "prettyspider");
​
        FSDataInputStream in=null;
        try {
            in = fs.open(new Path("input/hdfs-site.xml"));
​
            IOUtils.copyBytes(in, System.out, 4096, false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

Snipaste_2023-10-09_21-15-18.png

8.FileSystem写入,读取数据的过程

在理解相应过程之前,需要提前知道的知识

1.什么是pipeline管道

Snipaste_2023-10-09_23-49-44.png

Pipeline,中文翻译为管道。这是HDFS在上传文件写数据过程中采用的一种数据传输方式

客户端将数据块写入第一个数据节点,第一个数据节点保存数据之后再将块复制到第二个数据节点,后者保存后将其复制到第三个数据节点。

使用pipeline线性传输而不使用拓扑式传输的原因:

因为数据以管道的方式,顺序的沿着一个方向传输,这样能够充分利用每个机器的带宽,避免网络瓶颈和高延迟时的连接,最小化推送所有数据的延时 在线性推送模式下,每台机器所有的出口宽带都用于以最快的速度传输数据,而不是在多个接受者之间分配宽带

2.什么是ack应答相应

Snipaste_2023-10-09_23-52-50.png

ACK (Acknowledge character)即是确认字符,在数据通信中,接收方发给发送方的一种传输类控制字符。表示发来的数据已确认接收无误

在HDFS pipeline管道传输数据的过程中,传输的反方向会进行ACK校验,确保数据传输安全。

3.默认3副本存储策略

第一块副本:优先客户端本地,否则随机

第二块副本:不同于第一块副本的不同机架

第三块副本:第二块副本相同机架不同机器

1.写入数据过程

Snipaste_2023-10-09_23-48-28.png

1、HDFS客户端创建FileSystem对象实例DistributedFileSystem, FileSystem封装了与文件系统操作的相关方法。

2、调用DistributedFileSystem对象的create()方法,通过RPC请求NameNode创建文件。 NameNode执行各种检查判断:目标文件是否存在、父目录是否存在、客户端是否具有创建该文件的权限。检查通过,NameNode就会为本次请求记下一条记录,返回FSDataOutputStream输出流对象给客户端用于写数据。

3、客户端通过FSDataOutputStream开始写入数据。FSDataOutputStream是DFSOutputStream包装类。

4、客户端写入数据时,DFSOutputStream将数据分成一个个数据包(packet 默认64k),并写入一个内部数据队列(data queue)。 DFSOutputStream有一个内部类做DataStreamer,用于请求NameNode挑选出适合存储数据副本的一组DataNode,默认是3副本存储。DataStreamer将数据包流式传输到pipeline的第一个DataNode,该DataNode存储数据包并将它发送到pipeline的第二个DataNode。同样,第二个DataNode存储数据包并且发送给第三个(也是最后一个)DataNode。

5、DFSOutputStream也维护着一个内部数据包队列来等待DataNode的收到确认回执,称之为确认队列(ack queue),收到pipeline中所有DataNode确认信息后,该数据包才会从确认队列删除。

6、客户端完成数据写入后,在FSDataOutputStream输出流上调用close()方法关闭。

7、DistributedFileSystem联系NameNode告知其文件写入完成,等待NameNode确认。 因为namenode已经知道文件由哪些块组成(DataStream请求分配数据块),因此仅需等待最小复制块即可成功返回。 最小复制是由参数dfs.namenode.replication.min指定,默认是1.

2.读取数据过程

Snipaste_2023-10-09_23-58-28.png

1、HDFS客户端创建FileSystem对象实例DistributedFileSystem, FileSystem封装了与文件系统操作的相关方法。调用DistributedFileSystem对象的open()方法来打开希望读取的文件

2、DistributedFileSystem使用RPC调用namenode来确定文件中前几个块的块位置(分批次读取)信息 对于每个块,namenode返回具有该块所有副本的datanode位置地址列表,并且该地址列表是排序好的,与客户端的网络拓扑距离近的排序靠前

3、DistributedFileSystem将FSDataInputStream输入流返回到客户端以供其读取数据。FSDataInputStream类是DFSInputStream类的包装

4、客户端在FSDataInputStream输入流上调用read()方法。然后,已存储DataNode地址的DFSInputStream连接到文件中第一个块的最近的DataNode

数据从DataNode流回客户端,结果客户端可以在流上重复调用read()

5、当该块结束时,DFSInputStream将关闭与DataNode的连接,然后寻找下一个块的最佳datanode。这些操作对用户来说是透明的

所以用户感觉起来它一直在读取一个连续的流

客户端从流中读取数据时,也会根据需要询问NameNode来检索下一批数据块的DataNode位置信息

6、一旦客户端完成读取,就对FSDataInputStream调用close()方法

9.在运行jar包时,命令行参数是如何导入

public static void main(String[] args)

args是一个数组,用户获取命令行的参数,索引从0开始

在运行jar包时,会在家暴之后传入一定数目的参数,参数会被args数组接受,在程序中通过索引获取参数,进而实现程序的运行

由可变参数可以将参数的形式变为

public static void main(String... args)

10.文件模式匹配

HDFS文件系统中的模式匹配和java的模式匹配类似,知识对应的正则需要在适当的位置