HDFS如何解决海量数据存储及解决方案详解

HDFS组件

HDFS组件的基准测试

说明

一般在搭建完集群之后,运维人员需要对集群进行压力测试,对于HDFS来讲,主要是读写测试

写入测试

hadoop jar /export/server/hadoop-3.3.0/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.0-tests.jar TestDFSIO -write -nrFiles 10  -fileSize 10MB

读取测试

hadoop jar /export/server/hadoop-3.3.0/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.0-tests.jar  TestDFSIO -read -nrFiles 10 -fileSize 10MB 

在这里插入图片描述

Hadoop的MapReduce历史服务查看

说明

如果你开启了历史服务器组件,则你跑过的所有的MapReduce任务都可以在19888端口查看,同时可以通过后台的日志先查看任务详细的执行流程,以便排查错误

http://node1:19888

打开方式

http://node1:19888/

在这里插入图片描述

文件系统

概念

文件系统是一个软件,通过这个软件,用户不用关系具体的文件内容存储在磁盘的什么位置,直接就可以对文件操作

文件系统的分类

  • 本地磁盘文件系统

    类Windows文件系统:盘符体系(D盘,E盘)NTFS
    类Unix文件系统:    /目录
    
  • 光盘文件系统

    ISO镜像文件
    
  • 网络文件系统

    NFS: 使用网络来远程访问其他主机的文件,就像访问本机文件一样方便
    
  • 分布式文件系统

    1、分布式文件系统是由多态主机模拟出来的一个文件系统,文件是分散存储在不同的主机上
    2、分布式文件系统有很多种:
    1)、GFS
    GFS(Google File System)是Google公司为满足公司需求而开发的基于Linux的可扩展的分布式文件系统,用于大型的、分布式的、对大数据进行访问和应用,成本低,应用于廉价的普通硬件上,但不开源,暂不考虑。
    
    2)、TFS
    TFS(Taobao File System)是阿里巴巴为满足了淘宝对小文件存储的需求而开发的一个可扩展、高可用、高性能、面向互联网服务、开源的分布式文件系统,主要针对海量的非结构化数据,它构筑在普通的Linux机器集群上,可为外部提供高可靠和高并发的存储访问。TFS为淘宝提供海量小文件存储,通常文件大小不超过1M,这个也暂不考虑。
    
    3)、HDFS
    HDFS(Hadoop Distributed File System)。Hadoop分布式文件系统,适合运行在通用硬件上做分布式存储和计算,因为它具有高容错性和可扩展性的特点,可部署在廉价的机器上,适合大数据的处理,在离线批量处理大数据上有先天的优势。
    Hadoop是Apache Lucene创始人Doug Cutting开发的使用广泛的文本搜索库。它起源于Apache Nutch,后者是一个开源的网络搜索引擎,本身也是Luene项目的一部分。Aapche Hadoop架构是MapReduce算法的一种开源应用,是Google开创其帝国的重要基石。
    
    4)、MooseFS
    MooseFS 是来自波兰的开源且具备冗余容错功能的分布式 POSIX 文件系统,也是参照了 GFS 的架构,实现了绝大部分 POSIX 语义和 API,它支持通过FUSE方式将文件挂载操作,同时其提供的web管理界面非常方便查看当前的文件存储状态,对master服务器有单点依赖,用perl编写,用于中、大型文件应用,但性能相对较差,由于可能会实时访问所以暂不考虑。
    备注:POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准
    
    5)、FastDFS
    由淘宝的余庆先生所开发的一个开源分布式文件系统。它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。适合以文件为载体的在线服务,如相册网站、视频网站等等。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS搭建一套高性能的文件服务器集群提供文件上传、下载等服务。但是FastDFS部署有点麻烦,且它的SKD是不全的。
    
    6)、MogileFS
    MogileFS是一套高效开源的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上。支持多节点冗余,可实现自动的文件复制。不需要RAID,应用层可以直接实现RAID,不共享任何东西,通过集群接口提供服务工作于应用层,没有特殊的组件要求。使用HTTP方式通信。
    
    7)、GridFS
    MongoDB是一种知名的NoSql数据库,GridFS是MongoDB的一个内置功能,它用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等),是文件存储的一种方式,但是它是存储在MonoDB的集合中。它可以直接利用已建立的复制或分片机制,所以对于文件存储来说故障恢复和扩展都容易,且GridFS不产生磁盘碎片。
    
    8)、MinIO
    MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。它也是一个非常轻量的服务,可以很简单的和其他应用的结合。MinIO的特色在于简单、轻量级,对开发者友好,学习成本低,安装运维简单,开箱即用。
    
    9)、SeaweedFS
    SeaweedFS是基于go语言开发高度可扩展开源的分布式存储系统,能存储数十亿文件(最终受制于你的硬盘大小)、并且速度快,内存占用小。上手使用比fastDFS要简单很多,自带Rest API。对于中小型文件效率非常高,但是单卷最大容量被程序限制到30G,建议存储文件以100MB以内为主。
    
    10)、Ceph
    Ceph是Red Hat旗下一个成熟的分布式文件系统,而且还是一个有企业级功能的对象存储生态环境。该系统具备高性能、高可用性、高可扩展性、实时存储性等特点。虽然ceph很强大,但是学习成本高、安装运维复杂。Ceph用C++编写,存储容量可轻松达到PB级别。
    
    11)、GlusterFS
    GlusterFS 是由美国的 Gluster 公司开发的 POSIX 分布式文件系统(以 GPL 开源),它主要应用在集群系统中,具有高扩展性、高可用性、高性能、可横向扩展等特点,并且其没有元数据服务器的设计,让整个服务没有单点故障的隐患。该系统主要是为中大型文件设计的,存储容量可轻松达到PB。它存在扩容缩容影响服务器较多、遍历目录下文件耗时、小文件性能较差的缺点。
    

在这里插入图片描述

HDFS如何解决海量数据问题

存储方式

1、传统单机存储是纵向扩展存储空间(不断加硬盘),这种扩展是有限的
2、分布式存储是横向扩展存储空间(不断加主机),这种扩展几乎是无限的

文件查询问题

NameNode: 存储HDFS的文件的元数据,NodeName工作时,这些元数据会被加载到内存中,同时也会被持久化存储到硬盘上
   #元数据:类似派出所的户籍信息,描述文件除内容之外的额数据(文件的权限,大小,存储路径,Block信息)
   
   
DataNode: 具体存储文件数据的,这些数据最后分散在不同主机的硬盘上

在这里插入图片描述

HDFS的简介

1、HDFS(Hadoop Distributed File System) 是Hadoop分布式文件系统
2、HDFS主要是存储TB和PB,EB级别文件
3、HDFS上存储的文件只能追加写入(在尾部加入内容),不能随机修改(在中间修改),HDFS除了最后一个Bock之外,前边的所有的Block一旦定型,永远不能修改

4、HDFS的读写速度有延迟,不能保证实时,如果你对时效性要求比较高,则不要使用HDFS
5、HDFS适合存储大文件,不适合存储小文件:
  5.1)一个文件,不管大小,都会占用一条元数据,一条元数据大概是150字节
  5.2)在工作时,元数据是保存在NameNode主机的内存中,内存如果有限的情况下,保存的元数据数量也是有限的,NameNode主机内存固定的情况下,能存多少条元数据是固定的
  5.3)如果你存储太多的小文件,这些小文件会占用大量的元数据,会占用namenode大量的内存空间,会导致   NameNode内存空间不够用的问题。
 
 6、由于HDFS强调的是集群整体的性能,单机的性能可以很弱,机器可以很廉价(蚂蚁多了,力量也很强大)

HDFS的切片问题

1、默认情况下,HDFS是以Block为单位进行存储,每一个Block最大是128M,如果一个文件不足128M,则默认也是一个Block,所以Block是一个逻辑单位
2、举例:1.txt 300M 
         Block1 128M  
         Block2 128M 
         Block3 44M
3、我们可以去修改每个Block的大小:dfs.blocksize  134217728 字节  在hdfs-site.xml中做如下配置:
<property>
        <name>dfs.blocksize</name>
        <value>268435456</value>
</property>

在node1修改完之后,要将这个配置文件分发给node2和node3,然后重启hadoop

在这里插入图片描述

HDFS如何解决数据丢失问题-副本机制

1、每一个Block切片都会存储多个副本(默认是3个)
2、副本机制就是通过牺牲空间来换取数据的安全可靠性
3、我们可以通过dfs.replication参数来修改副本数量,在hdfs-site.xml中做如下配置:

<property>
        <name>dfs.replication</name>
        <value>2</value>
</property>

在node1修改完之后,要将这个配置文件分发给node2和node3,然后重启hadoop



#在Linux如何造一个任意大小的测试文件
dd if=/dev/zero of=my_file bs=1M count=300       #300M文件
dd if=/dev/zero of=my_file bs=1G count=1         #1G文件

在这里插入图片描述

HDFS的机架感知

  • 概念

    1、一个Block默认有3个副本,当存一个BLock的时候,每一个副本应该存放到哪一台主机有一定的策略,这个策略就被称为机架感知
    
    /**
     * The class is responsible for choosing the desired number of targets
     * for placing block replicas.
     * The replica placement strategy is that if the writer is on a datanode,
     * the 1st replica is placed on the local machine, 
     * otherwise a random datanode. The 2nd replica is placed on a datanode
     * that is on a different rack. The 3rd replica is placed on a datanode
     * which is on a different node of the rack as the second replica.
     */
    @InterfaceAudience.Private
    public class BlockPlacementPolicyDefault extends BlockPlacementPolicy {
    
    2、机架感知策略
     第一个副本如果客户端就是集群内部的某台主机,则第一个副本直接本地存储放在客户端主机上,否则随机选择一台主机
     第二个副本放在和第一个副本不同的机架上
     第三个副本放在和第二个副本同一个机架不同主机上
    

在这里插入图片描述

HDFS文件如何让用户访问-名称空间

1、为了让客户不去关心HDFS文件复杂的元数据管理,我们只需要给用户暴露一个唯一的目录树结构的访问路径鸡即可,这个被称为名称空间。
访问的主机本身就在集群内部:/benchmarks/TestDFSIO/io_data/test_io_0
访问的主机本身就在集群外部:hdfs://node1:8020/benchmarks/TestDFSIO/io_data/test_io_0

2、HDFS的路径和Linux主机的本地路径没有关系

HDFS的元数据

1、元数据是描述文件特征的数据,不是文件内容
2、元数据包含的信息:
  2.1)文件自身属性信息
   文件名称、权限,修改时间,文件大小,副本数,Block大小。
   	-rw-r--r--	root	supergroup	6 B	Jan 12 21:34	3	128 MB	a.txt
  2.2) 文件块位置映射信息
  记录文件块和DataNode之间的映射信息,即哪个块位于哪个节点上。
  a.txt 300M
  ------------------------------
  {
    blk1:node2,node1,node3
    blk2:node3,node1,node2
    blk3:node1,node2,node3
   }

HDFS的架构

NameNode: 
 1、存储HDFS的文件的元数据,NodeName工作时,这些元数据会被加载到内存中,同时也会被持久化存储到硬盘
 2、NameNode接受客户端读写请求,因为NameNode知道每一个文件都存在哪个DataNode上
 3、NameNode接受各个DataNode的心跳信息、Block汇报信息、资源使用情况(硬盘)
 4、如果NameNode一旦挂掉,整个集群将不能工作
    
DataNode: 
 1、存具体的文件数据
 2、定时向NameNode汇报心跳信息、Block汇报信息、资源使用情况
 3、如果某个DataNode挂掉,只要丢失Block的信息其他主机有,则不影响集群运行

在这里插入图片描述

HDFS的Shell命令

介绍

1、HDFS的网页页面在2.x版本时是没有任何操作菜单,只能查看,则必须使用Shell命令来操作
2、学习HDFS的Shell命令可以在不查看页面的情况下对HDFS上的文件进行增删改查

语法

hadoop fs 参数     #该方式可以操作任何文件系统:磁盘文件系统、HDFS文件系统
hdfs  dfs  参数    #该方式只能操作HDFS文件系统

操作

#1、查看指定路径的当前目录结构
hadoop fs -ls /
hdfs dfs  -ls /

#2、递归查看指定路径的目录结构
hadoop fs -lsr /   #已淘汰
hadoop fs -ls -R /  #用这个

#3、查看目录下文件的大小
hadoop fs -du -h /

#4、文件移动(HDFS之间)
hadoop fs -mv /a.txt /dir1

#5、文件复制(HDFS之间)
hadoop fs -cp /dir1/a.txt /dir1/b.txt

#6、删除操作   !!!!!!!!!!!!!!!!!!
hadoop fs -rm /dir1/b.txt  #删文件
hadoop fs -rm -r /dir1     #删目录   

#7、文件上传(本地文件系统到HDFS文件系统)  --- 复制操作   !!!!!!!!!!!!
hadoop fs -put a.txt /dir1 

#8、文件上传(本地文件系统到HDFS文件系统)  --- 剪切操作
hadoop fs -moveFromLocal test1.txt /

#8、文件下载(HDFS文件系统到本地文件系统)   !!!!!!!!!!!
hadoop fs -get /aaa.txt  /root 

#9、文件下载(HDFS文件系统到本地文件系统)
hadoop fs -getmerge /dir/*.txt /root/123.txt 

#10、将小文件进行合并,然后上传到HDFS
hadoop fs -appendToFile *.txt  /hello.txt    
hadoop fs -appendToFile 1.txt 2.txt 3.txt  /hello.txt    
hadoop fs -appendToFile /root/*  /hello.txt  

#11、查看HDFS文件内容
hadoop fs -cat /dir1/1.txt

#12、在HDFS创建文件夹     !!!!!!!!!!!!
hadoop fs -mkdir /my_dir

#13、修改HDFS文件的权限
hadoop fs -chmod -R 777 /dir1

#14、修改HDFS的所属用户和用户组

useradd hadoop
passwd hadoop

hadoop fs -chown -R hadoop:hadoop /dir

回收站配置

#在每个节点的core-site.xml上配置为1天,1天之后,回收站的资源自动
<property>
  <name>fs.trash.interval</name>
  <value>1440</value>
  <description>minutes between trash checkpoints</description>
</property>

#需要重启Hadoop

HDFS的安全模式

  • 介绍

    1、在HDFS启动时,HDFS会自动的进入安全模式,在该模式下进行Block数量的检测和自我修复,当BLock数量完整率达到99.9%时,会自动的离开安全模式
    
    2、安全模式停留多长时间不固定,你的Block数量越多,检测的时间越长,安全模式停留时间越长
    
    3、在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。
    
  • 操作命令

    hdfs  dfsadmin -safemode  get     #查看安全模式状态
    hdfs  dfsadmin -safemode  enter   #进入安全模式
    hdfs  dfsadmin -safemode  leave   #离开安全模式
    
    hdfs dfsadmin -safemode forceExit  #强制离开安全模式
    

HDFS的读写流程

写入流程

在这里插入图片描述

读取流程

在这里插入图片描述

HDFS的元数据管理

  • 原理

在这里插入图片描述
在这里插入图片描述

1)当触发checkpoint操作条件(每隔一个小时,或者edits文件达到64M)时,SNN发生请求给NN滚动edits log。然后NN会生成一个新的编辑日志文件:edits new,便于记录后续操作记录。
2)同时SNN会将edits文件和fsimage复制到本地(使用HTTP GET方式)。
3)SNN首先将fsimage载入到内存,然后一条一条地执行edits文件中的操作,使得内存中的fsimage不断更新,这个过程就是edits和fsimage文件合并。合并结束,SNN将内存中的数据dump生成一个新的fsimage文件。
3)SNN将新生成的Fsimage new文件复制到NN节点。
4)至此刚好是一个轮回,等待下一次checkpoint触发SecondaryNameNode进行工作,一直这样循环操作。
  • 查看日志文件内容

    hdfs oev -i edits_0000000000000000011-0000000000000000025 -o edits.xml
    

HDFS的JavaAPI操作(重点)

  • 介绍

    使用Java提供的API来对HDFS上的文件进行增删查,相当于实现9870页面的鼠标操作和Shell命令操作
    
  • 核心类

    FileSystem
    Configuration
    
  • 代码

    package pack01_hdfs;
    
    
    import org.apache.commons.compress.utils.IOUtils;
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.*;
    import org.junit.Test;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.Arrays;
    
    
    public class Test1HDFS {
        //文件的合并上传-方式2
        @Test
        public void test9AppendToFile()throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:获取HDFS目标文件的输出流-写
            FSDataOutputStream outputStream = fileSystem.create(new Path("/append2.txt"));
    
            //3:获取本地每一个小文件的输入流
            File file = new File("E:\\input");
    
            File[] files = file.listFiles();
            for (File file1 : files) {
                FileInputStream inputStream = new FileInputStream(file1);
                //4:实现文件的合并
                IOUtils.copy(inputStream,outputStream);
                IOUtils.closeQuietly(inputStream);
            }
    
            //5:关流
            IOUtils.closeQuietly(outputStream);
    
        }
        //文件的合并上传-方式1
        @Test
        public void test8AppendToFile()throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:获取HDFS目标文件的输出流-写
            FSDataOutputStream outputStream = fileSystem.create(new Path("/append.txt"));
    
            //3:获取本地每一个小文件的输入流
            FileInputStream inputStream1 = new FileInputStream("E:\\input\\a.txt");
            FileInputStream inputStream2 = new FileInputStream("E:\\input\\b.txt");
            FileInputStream inputStream3 = new FileInputStream("E:\\input\\c.txt");
    
            //4:实现文件的合并
            IOUtils.copy(inputStream1,outputStream);
            IOUtils.copy(inputStream2,outputStream);
            IOUtils.copy(inputStream3,outputStream);
    
            //5:关流
            IOUtils.closeQuietly(inputStream3);
            IOUtils.closeQuietly(inputStream2);
            IOUtils.closeQuietly(inputStream1);
            IOUtils.closeQuietly(outputStream);
    
        }
    
        //文件的下载-方式2
        @Test
        public void test7Upload()throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:文件的上传
            fileSystem.copyFromLocalFile(new Path("E:\\big.txt"),new Path("/bigg.txt"));
        }
    
        //文件的下载-方式2
        @Test
        public void test6Download2()throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:文件的下载
            fileSystem.copyToLocalFile(new Path("/big.txt"),new Path("E:\\big2.txt"));
        }
        //文件的下载-方式1
        @Test
        public void test5Download1()throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:获取HDFS文件的输入流-读
            FSDataInputStream inputStream = fileSystem.open(new Path("/big.txt"));
    
            //3:获取目标文件的输出流-写
            FileOutputStream outputStream = new FileOutputStream("E:\\big.txt");
    
            /*
            //4:完成文件的复制
            byte[] bytes = new byte[1024];
            while (true){
                int len = inputStream.read(bytes);
                if(len == -1){
                    break;
                }
                outputStream.write(bytes,0,len);
            }
            //5:关流
            outputStream.close();
            inputStream.close();
             */
    
            //4:完成文件的复制
            IOUtils.copy(inputStream,outputStream);
            //5:关流
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        }
        //从HDFS删除文件
        @Test
        public void test4Delete() throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:从HDFS删除文件
            fileSystem.delete(new Path("/itcast"),true);
        }
        //在HDFS上创建目录(递归创建)
        @Test
        public void test3Mkdir() throws  Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:在HDFS创建目录
            fileSystem.mkdirs(new Path("/itcast/ky7/hdfs"));
        }
    
        //遍历HDFS的文件信息
        @Test
        public void test2ListFiles() throws Exception{
            //1:获取FileSystem对象
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            //2:获取指定目录下的所有文件元数据信息
            RemoteIterator<LocatedFileStatus> iterator =
                    fileSystem.listFiles(new Path("/"), true);
    
            //3:遍历集合
            while (iterator.hasNext()){
                //4、获取每一个文件的元数据信息
                LocatedFileStatus fileStatus = iterator.next();
    
                //5、打印每一个文件的元数据信息-文件绝对路径
                System.out.print(fileStatus.getPath());
    
                //6、Block信息
                //6.1 获取每一个BLock信息
                BlockLocation[] blockLocations = fileStatus.getBlockLocations();
                System.out.println("----"+blockLocations.length);  //输出每个文件的Block数 3
                for (BlockLocation blockLocation : blockLocations) {
                    //6.2获取每一个Block的副本存储主机位置
                    String[] hosts = blockLocation.getHosts();
                    System.out.println(Arrays.toString(hosts));
                }
            }
        }
    
        @Test
        public void test1GetFileSytem() throws Exception {
            FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
    
            System.out.println(fileSystem);
        }
    }
    

HDFS的远程拷贝命令

  • 集群内部拷贝

    #推数据
    scp  -r  /root/test/  root@192.168.88.161:/root/
    
    #拉数据
    scp root@192.168.88.162:/root/test.txt /root/test.txt
    
  • 集群之间拷贝

    hadoop distcp hdfs://node1:8020/a.txt  hdfs://hadoop1:8020/
    

HDFS的归档机制(面试题)

  • 介绍

    如果HDFS上有很多的小文件,会占用大量的NameNode元数据的内存空间,需要将这些小文件进行归档(打包),归档之后,相当于将多个文件合成一个文件,而且归档之后,还可以透明的访问其中的每一个文件
    
  • 操作

    #数据准备
    hadoop fs -mkdir /config
    hadoop fs -put /export/server/hadoop-3.3.0/etc/hadoop/*.xml  /config
    
    #创建归档文件
    hadoop archive -archiveName test.har -p /config  /outputdir
    hadoop  fs -rm -r /config
    
    #查看合并后的小文件全部内容 
    hadoop fs -cat /outputdir/test.har/part-0
    
    #查看归档中每一个小文件的名字 
    hadoop fs -ls har://hdfs-node1:8020/outputdir/test.har
    
    #查看归档中其中的一个小文件内容
    hadoop fs -cat har:///outputdir/test.har/core-site.xml
    
    #还原归档文件
    hadoop fs -mkdir /config
    hadoop fs -cp har:///outputdir/test.har/*    /config
    
  • 注意点

    1.	Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。Hadoop archive的扩展名是*.har;
    2.	创建archives本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要提前启动Yarn集群; 
    3.	创建archive文件要消耗和原文件一样多的硬盘空间;
    4.	archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;
    5.	archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为它们是定期存档的,比如每周或每日;
    6.	当创建archive时,源文件不会被更改或删除;
    

HDFS的权限问题

  • 操作
hadoop fs -chmod 750 /user/itcast/foo            //变更目录或文件的权限位
hadoop fs -chown  :portal /user/itcast/foo       // 变更目录或文件的所属用户
hadoop fs -chgrp itcast _group1 /user/itcast/foo //变更用户组
  • 原理

    1、HDFS的权限有一个总开关,在hdfs-site.xml中配置,只有该参数的值为true,则HDFS的权限才可以起作用
      dfs.permissions.enabled    #在Hadoop3.3.0中该值默认是 true  
    
  • Java代码权限问题

    //如果在通过JavaAPI来访问HDFS,遇到权限问题,有3中解决方案
    1、关闭HDFS权限的总开关,设置  dfs.permissions.enabled 为 false
    2、使用 hadoop fs -chmod -R 777 /tmp 修改权限
    3、使用root用户的身份去获取FileSystem对象
         FileSystem fileSystem =
                    FileSystem.get(new URI("hdfs://node1:8020"), new Configuration(),"root");
    

HDFS的动态上下线

动态扩容

纵向扩容:加硬盘
横向扩容:加主机
  • 介绍

    1、当集群的存储容量达到上限时,我们可以通过添加主机的方式来扩展DataNode节点,来横向增加集群的存储空间
    2、我们在动态扩容时,不要一影响当前集群的正常工作
    
  • 操作

    ==================1、基础环境配置====================
    1、从node1克隆一台主机:node4
    2、修改node4的Mac地址、IP地址为164,主机名为node4
    3、关闭node4的防火墙、安装JDK,关闭Selinux (已做)
    
    4、node1、node2、node3、node4要修改域名映射
    192.168.88.161 node1 node1.itcast.cn
    192.168.88.162 node2 node2.itcast.cn
    192.168.88.163 node3 node3.itcast.cn
    192.168.88.164 node4 node4.itcast.cn
    
    5、node1、node2、node3、node4重新构建免密登录
    5.1)在node4上,生成一个密钥对:ssh-keygen -t rsa
    5.2)在node4上,将node4的公钥发送给node1:ssh-copy-id node1
    5.3)将node1上,将所有公钥发送给:node2,node3,node4
       scp /root/.ssh/authorized_keys node2:/root/.ssh
       scp /root/.ssh/authorized_keys node3:/root/.ssh
       scp /root/.ssh/authorized_keys node4:/root/.ssh
       
    6、在node4上,删除Hadoop的所有痕迹
       6.1)删除Hadoop安装包: rm -fr /export/server/hadoop-3.3.0/
       6.2)删除Hadoop数据:   rm -fr /export/data/hadoop-3.3.0/
       6.3)删除Hadoop的环境变量:vim /etc/profile
    
    ==================1、Hadoop上线核心配置====================
    
    7、在node1上修改namenode(node1)节点workers配置文件,增加新节点主机名
     vim /export/server/hadoop-3.3.0/etc/hadoop/workers 
     node1
     node2
     node3
     node4
    8、在node1上,将Hadoop分发给node4
     scp -r /export/server/hadoop-3.3.0 node4:/export/server
    
    9、在node4上,新机器上配置hadoop环境变量
    vim /etc/profile
    
    export HADOOP_HOME=/export/server/hadoop-3.3.0
    export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
    
    
    最后:source /etc/profile
    
    10、在node4上启动datanode
    hdfs --daemon start datanode
    11、通过页面查看
    http://node1:9870/dfshealth.html#tab-datanode
    
    
    
    #---------------设置负载均衡---------------
    #设置在负载均衡期间DataNode在数据搬移时,能够使用的最大带宽(100M)
    hdfs dfsadmin -setBalancerBandwidth 104857600
    
    #当不同主机之间存储的比率超过5%时,会自动进行负载均衡操作
    hdfs balancer -threshold 5
    

在这里插入图片描述

动态缩容

1、在node1上,保证你的hdfs-site.xml文件中有以下黑名单配置
<property>
        <name>dfs.hosts.exclude</name>
        <value>/export/server/hadoop-3.3.0/etc/hadoop/excludes</value>
</property>

2、在node1上,将你要退役的主机的主机名加入黑名单,编辑以下文件,加入node4
  vim  /export/server/hadoop-3.3.0/etc/hadoop/excludes
  
3、在ndoe1上,刷新集群
 hdfs dfsadmin -refreshNodes
 
4、通过datanode页面查看node4的退役状态
 http://node1:9870/dfshealth.html#tab-datanode
 
 #---------------设置负载均衡---------------
#设置在负载均衡期间DataNode在数据搬移时,能够使用的最大带宽(100M)
hdfs dfsadmin -setBalancerBandwidth 104857600

#当不同主机之间存储的比率超过5%时,会自动进行负载均衡操作
hdfs balancer -threshold 5

在这里插入图片描述

HDFS的高可用

介绍

1、HDFS的高可用是由NameNode组成,一个是Active状态的NameNode,一个是Standby状态的NameNode
2、Journal Node集群两个NamNode之间元数据的同步,同步的数据是日志文件Edits,由NameNode自己完成fsimage文件的生成,没有SecondaryNameNode
3、两个NameNode的主备切换,是由ZKFC和Zookeeper集群共同来完成
  3.1 正常情况下由ZKFC来监控 Active NameNode的健康状态,一旦发现主NameNode健康不良,则立刻通知Zookeeper,Zookeeper会通知备ZKFC,然后备ZKFC会改变备NameNode状态由Standby改为Active,备NameNode成为新的主节点

在这里插入图片描述

脑裂问题

  • 原因

    由于极端情况下,主NameNode发生了假死现象,临时假死,后来又复活,这样原来的主NameNode状态是Active,后来的备用NameNode状态也改为Active,这样就会有两个Active状态的NameNode,会造成元数据的管理混乱,就相当于一个大脑被拆分了。
    
  • 解决方案

    方案1:调用旧Active状态的RPC接口中的相关方法,将其状态由Active强制改为StandBy
    方案2:如果方案1没有实现,则ZK会远程登录到旧Active的NameNode主机上,将NameNode进程杀死
    

环境搭建

  • 搭建方案

在这里插入图片描述

  • 操作步骤

    • 1、备份单节点Hadoop

      #在node1,node2,node3主机上,分别执行以下操作:
       mv /export/server/hadoop-3.3.0 /export/server/hadoop-3.3.0_bak
      
    • 2、解压Hadoop

      tar -xvf hadoop-3.3.0-Centos7-64-with-snappy.tar.gz -C /export/server/
      
    • 3、配置环境变量(可以不做)

      #在node1,node2,node3主机上,分别执行以下操作:
      vim /etc/profile
      
      export HADOOP_HOME=/export/server/hadoop-3.3.0
      export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
      
      
      source /etc/profile
      
    • 4、配置hadoop-env.sh文件

      cd /export/server/hadoop-3.3.0/etc/hadoop
      
      vim hadoop-env.sh
      
      
      export JAVA_HOME=/export/server/jdk1.8.0_241
      
      export HDFS_NAMENODE_USER=root
      export HDFS_DATANODE_USER=root
      export HDFS_SECONDARYNAMENODE_USER=root
      export YARN_RESOURCEMANAGER_USER=root
      export YARN_NODEMANAGER_USER=root
      export HDFS_JOURNALNODE_USER=root
      export HDFS_ZKFC_USER=root
      
    • 5、core-site.xml

      
      <configuration>
      	<!-- HA集群名称,该值要和hdfs-site.xml中的配置保持一致 -->
      	<property>
      		<name>fs.defaultFS</name>
      		<value>hdfs://mycluster</value>
      	</property>
      
      	<!-- hadoop本地磁盘存放数据的公共目录 -->
      	<property>
      		<name>hadoop.tmp.dir</name>
      		<value>/export/data/ha-hadoop</value>
      	</property>
      
      	<!-- ZooKeeper集群的地址和端口-->
      	<property>
      		<name>ha.zookeeper.quorum</name>
      		<value>node1:2181,node2:2181,node3:2181</value>
      	</property>
      </configuration>
      
    • 6、配置 hdfs-site.xml

      <configuration>
      		<!--指定hdfs的nameservice为mycluster,需要和core-site.xml中的保持一致 -->
      	<property>
      		<name>dfs.nameservices</name>
      		<value>mycluster</value>
      	</property>
      	
      	<!-- mycluster下面有两个NameNode,分别是nn1,nn2 -->
      	<property>
      		<name>dfs.ha.namenodes.mycluster</name>
      		<value>nn1,nn2</value>
      	</property>
      
      	<!-- nn1的RPC通信地址 -->
      	<property>
      		<name>dfs.namenode.rpc-address.mycluster.nn1</name>
      		<value>node1:8020</value>
      	</property>
      
      	<!-- nn1的http通信地址 -->
      	<property>
      		<name>dfs.namenode.http-address.mycluster.nn1</name>
      		<value>node1:9870</value>
      	</property>
      
      	<!-- nn2的RPC通信地址 -->
      	<property>
      		<name>dfs.namenode.rpc-address.mycluster.nn2</name>
      		<value>node2:8020</value>
      	</property>
      	
      	<!-- nn2的http通信地址 -->
      	<property>
      		<name>dfs.namenode.http-address.mycluster.nn2</name>
      		<value>node2:9870</value>
      	</property>
      
      	<!-- 指定NameNode的edits元数据在JournalNode上的存放位置 -->
      	<property>
      		<name>dfs.namenode.shared.edits.dir</name>
      		<value>qjournal://node1:8485;node2:8485;node3:8485/mycluster</value>
      	</property>
      	
      	<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
      	<property>
      		<name>dfs.journalnode.edits.dir</name>
      		<value>/export/data/journaldata</value>
      	</property>
      
      	<!-- 开启NameNode失败自动切换 -->
      	<property>
      		<name>dfs.ha.automatic-failover.enabled</name>
      		<value>true</value>
      	</property>
      
      	<!-- 指定该集群出故障时,哪个实现类负责执行故障切换 -->
      	<property>
      		<name>dfs.client.failover.proxy.provider.mycluster</name>
      		<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
      	</property>
      
      	<!-- 配置隔离机制方法-->
      	<property>
      		<name>dfs.ha.fencing.methods</name>
      		<value>sshfence</value>
      	</property>
      	
      	<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
      	<property>
      		<name>dfs.ha.fencing.ssh.private-key-files</name>
      		<value>/root/.ssh/id_rsa</value>
      	</property>
      	
      	<!-- 配置sshfence隔离机制超时时间 -->
      	<property>
      		<name>dfs.ha.fencing.ssh.connect-timeout</name>
      		<value>30000</value>
      	</property>
      </configuration>
      
      
    • 配置mapred-site.xml

      <configuration>
      <!-- 指定mr框架为yarn方式 -->
      <property>
      	<name>mapreduce.framework.name</name>
      	<value>yarn</value>
      </property>
      
      <property>
        <name>yarn.app.mapreduce.am.env</name>
        <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
      </property>
      
      <property>
        <name>mapreduce.map.env</name>
        <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
      </property>
      
      <property>
        <name>mapreduce.reduce.env</name>
        <value>HADOOP_MAPRED_HOME=${HADOOP_HOME}</value>
      </property>
      </configuration>
      
    • 配置yarn-site.xml

      <configuration>
      <!-- 开启RM高可用 -->
      <property>
      	<name>yarn.resourcemanager.ha.enabled</name>
      	<value>true</value>
      </property>
      
      <!-- 指定RM的cluster id -->
      <property>
      	<name>yarn.resourcemanager.cluster-id</name>
      	<value>yrc</value>
      </property>
      
      <!-- 指定RM的名字 -->
      <property>
      	<name>yarn.resourcemanager.ha.rm-ids</name>
      	<value>rm1,rm2</value>
      </property>
      
      <!-- 分别指定RM的地址 -->
      <property>
      	<name>yarn.resourcemanager.hostname.rm1</name>
      	<value>node1</value>
      </property>
      
      <property>
      	<name>yarn.resourcemanager.hostname.rm2</name>
      	<value>node2</value>
      </property>
      
      <property>
          <name>yarn.resourcemanager.webapp.address.rm1</name>
          <value>node1:8088</value>
      </property>
      
      <property>
          <name>yarn.resourcemanager.webapp.address.rm2</name>
          <value>node2:8088</value>
      </property>
      
      <!-- 指定zk集群地址 -->
      <property>
      	<name>yarn.resourcemanager.zk-address</name>
      	<value>node1:2181,node2:2181,node3:2181</value>
      </property>
      
      <property>
      	<name>yarn.nodemanager.aux-services</name>
      	<value>mapreduce_shuffle</value>
      </property>
      
      <!-- 是否将对容器实施物理内存限制 -->
      <property>
          <name>yarn.nodemanager.pmem-check-enabled</name>
          <value>false</value>
      </property>
      
      <!-- 是否将对容器实施虚拟内存限制。 -->
      <property>
          <name>yarn.nodemanager.vmem-check-enabled</name>
          <value>false</value>
      </property>
      </configuration>
      
    • 配置workers

      node1
      node2
      node3
      
    • 分发

      cd /export/server
      scp -r hadoop-3.3.0 root@node2:$PWD
      scp -r hadoop-3.3.0 root@node3:$PWD
      

启动集群

#为防止主备切换失败,在node1,node2,node3安装以下软件包,保证不会发生脑裂
yum install psmisc -y
  • HA集群的初始化(只在第一次执行)

    • 启动zk集群

      #在node1,node2,node3分别执行以下的命令
      /export/server/zookeeper-3.4.6/bin/zkServer.sh start
      
    • 手动提前启动JN进程(node1 node2 node3分别启动

      hdfs --daemon start journalnode
      
    • 初始化namenode

      #在node1初始化namenode
      hdfs namenode -format
      
      #把node1初始化的数据完整复制一份给node2 保证两个nn初始化状态及数据是一致的
      #hdfs namenode –bootstrapStandby
      
      scp -r /export/data/ha-hadoop/ root@node2:/export/data/
      
      
    • 格式化ZKFC(在node1上执行即可)

      首次启动谁是active取决于在哪台机器执行该命令

      相当于首次选举是用户指定谁是老大

      hdfs zkfc -formatZK
      
  • HA集群的启动

    • 在node1上,启动hdfs集群

      start-dfs.sh
      
    • 在node1上,启动yarn集群

      start-yarn.sh
      
    • 在node1上,启动历史任务

      mapred --daemon start historyserver 
      
  • 后续启动和关闭

    1、以上的启动至用于刚搭建完集群的第一次启动使用
    2、以后高可用集群的启动和关闭直接使用以下命令:
      start-all.sh
      stop-all.sh
    

验证

  • 验证HDFS高可用

    1、网页访问NameNode
    http://node1:9870/
    http://node2:9870/
    
    2、文件上传
    hadoop fs -put a.txt /
    
    3、杀死主NameNode,观察备用NameNode是否称为主节点
     kill -9 9024 
    
  • 验证Yarn高可用

    1、网页访问NameNode
    http://node1:8088/
    http://node2:8088/
    
    #1、查看两个ResourceManager的状态
    yarn rmadmin -getServiceState rm1  #active
    yarn rmadmin -getServiceState rm2  #standby
    
    #2、在状态为active的主机中,杀死ResourceManager进程
    kill -9 ResourceManager进程号
    
    #3、查看ResourceManager状态
    yarn rmadmin -getServiceState rm1/rm2
    
    
    #4、求PI值
    
    hadoop jar /export/server/hadoop-3.3.0/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.0.jar pi 2 10000
    
    
    #19888和8088的区别?
    
    8088页面:  Yarn集群的信息 + 正在运行的任务 + 已经执行完成的任务
    19888页面: 已经执行完成的任务
    
    #8020和9870的区别?
    8020端口: 是HDFS客户端和NameNode之间的内部数据通信端口
    9870端口: 是浏览器和网页服务器之间的访问端口
    

如何还原单节点

1:在node1中
stop-all.sh
cd /export/server/
mv hadoop-3.3.0 hadoop-3.3.0_ha
mv hadoop-3.3.0_bak hadoop-3.3.0

2:在node2中
cd /export/server/
mv hadoop-3.3.0 hadoop-3.3.0_ha
mv hadoop-3.3.0_bak hadoop-3.3.0

3:在node3中
cd /export/server/
mv hadoop-3.3.0 hadoop-3.3.0_ha
mv hadoop-3.3.0_bak hadoop-3.3.0

4:在node1中
start-all.sh

#可以将之前动态添加的node4的信息删除

HA(高可用) + Federation*(联邦)

在这里插入图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留不住的人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值