HDFS的构架和使用

构架

1.主从架构

  • 主从架构
  • Namenode
    • 接受客户端请求
    • 管理:从节点、数据
    • 维护内存中的元数据
  • DataNode
    • 真正的读写操作,与文件系统

2、读写流程

写的流程

  • 用户操作客户端提交写文件请求给Namenode,NameNode接受写请求
    • hdfs dfs -put /export/datas/wordcount.txt /wordcount/input
    • 检测源和目标是存在
  • 客户端将文件进行拆分,首先提交第一个块的请求给NameNode
    • 主要请求Namenode将数据到底写在什么位置
  • NameNode根据所有DataNode的存活【live】以及活跃性【心跳不正常,但是没达到隔离的条件】以及每台DataNode存储的空间,来选择该块存储的位置,返回对应的DataNode的地址【三个副本的存储地址】
    • live nodes:正常的 节点
    • Decommissioning Nodes :被隔离的节点
    • dead node:没有心跳的节点
  • 客户端拿到该块的三个地址,通过机架感知【自动计算客户端到达每个地址的网络路由】,选举最近的地址,然后将块提交给最近的DataNode
  • 客户端会与该DataNode构建通信管道【pipeline】,将数据从本地读取到缓存中,然后划分每个package发送给第一个DataNode,该DataNode收到每一个package,就返回一个ack确认
  • 第一个地址会接收到客户端写入的数据块会与第二个地址构建数据通道【pipeline】,客户端的每个package,会通过第一个地址的管道给第二个地址,第二个地址与第三个地址构建通道,将package发送给第三个地址
  • 第三个地址的ack返回给第二个地址,第二个地址将ack返回给第一个地址,第一个地址将整体的三分的ack返回给客户端
  • 以此往复发送每个package,直到整个块的数据全部发完
  • 重复第二个步骤,请求下一个块
  • 整个所有数据块写完,客户端提交给Namenode结果,Namenode记录元数据

在这里插入图片描述

读的流程

  • 客户端提交读文件请求给NameNode
  • Namenode查询元数据,返回该文件对应的所有块的地址给客户端
  • 客户端根据机架感知来获取每个块离自己最近的位置
  • 连接所有块的dataNode获取每个块的数据
  • 将所有块进行合并,发回给用户
    在这里插入图片描述

HDFS的客户端操作

1、启动方式

  • 第一种方式:单进程启动 【用的比较少】

    • 比较麻烦,每个进程需要执行一条命令,适合于特殊进程的启动

      sbin/hadoop-daemon.sh:用于启动hdfs的进程
      #namenode
      sbin/hadoop-daemon.sh start namenode
      #datanode
      sbin/hadoop-daemon.sh start datanode
      #secondarynamenode
      sbin/hadoop-daemon.sh start secondarynamenode
      
      • 如果遇到报错:no main class
        • 进程名称写错了
        • 例如:start datenode
    • sbin/yarn-daemon.sh:用于启动yarn的进程

      #resourcemanager
      sbin/yarn-daemon.sh start resourcemanager
      #nodemanager
      sbin/yarn-daemon.sh start nodemanager
      
    • mr-jobhistory-daemon.sh:MapReduce的一个监控程序的进程

  • 第二种方式:分类别启动 【最常用的 方式,一般会结合第一种方式使用】

    • dfs:start-dfs.sh stop-dfs.sh
    • yarn:start-yarn.sh stop-yarn.sh
  • 第三种方式:启动所有进程【不推荐使用,一般不用】

    • 启动和关闭所有hdfs以及yarn的进程的
    • sbin/start-all.sh
    • sbin/stop-all.sh

2.基本文件操作

  • HDFS的客户端命令:hdfs

  • 用法:Usage: hdfs [–config confdir] COMMAND

    • 以前老版本的hadoop0或者hadoop1,hdfs和yarn是没有独立的客户端的
    • 客户端:hadoop
    • hadoop jar xx.jar = yarn jar xxx.jar
    • hadoop fs -rm -r = hdfs dfs -rm -r
  • 上传:本地文件系统到HDFS

    • put、copyfromlocal

      hdfs dfs -put /export/datas/wordcount.txt /wordcount/input/
      
  • 下载:hdfs到本地文件系统

    • get、copytolocal

      hdfs dfs -get /wordcount/input/wordcount.txt ~/
      
  • 查看:cat

    hdfs dfs -cat /wordcount/output1/part-r-00000
    
  • 列举:ls

    #如果使用hdfs客户端命令操作,就是操作hdfs
    hdfs dfs -ls /
    #如果直接使用命令,就在操作linux
    ls /
    
  • 删除:rm

    hdfs dfs -rm -r /wordcount/output1
    #回收站的清除时间:7天
    <property>
        <name>fs.trash.interval</name>
        <value>10080</value>
    </property>
    
    hdfs dfs -rm -skipTrash /wordcount/input/wordcount.txt
    
  • 复制:cp

    hdfs dfs -cp /wordcount/input/wordcount.txt /tmp/
    
  • 剪切:mv

    hdfs dfs -cp /tmp/wordcount.txt /wordcount/
    
  • 创建目录:mkdir

    hdfs dfs -mkdir -p /hdfs/client
    
  • 改权限:chmod

    hdfs dfs -chmod 777 /tmp
    
  • 手动清空回收站

    hdfs dfs -expunge
    
  • HDFS相对路径:当前用户在hdfs上的家目录

    hdfs dfs -ls  = hdfs dfs -ls /user/root
    

3.管理操作

  • namenode -format:用于第一次启动hdfs之前才需要格式化

    • 会初始化整个集群的信息
      • 集群id
      • 元数据文件
    • NameNode启动时会读取元数据文件中的元数据加载到内存
  • dfsadmin:hdfs的管理员操作命令

    • report:汇报,可以打印集群当前的状态信息

    • safemode:安全模式

    • refreshNodes:刷新节点信息

      • 当需要添加一个节点的时候,需要手动刷新,重新读取slaves文件
      • 如何不停机加机器
        • 准备一台机器,环境与所有机器一致
        • 拷贝一份hadoop到新机器上,要删除hadoopDatas中所有内容
        • 修改所有机器的slaves文件,添加这台机器的地址
        • 添加配置: dfs.hosts = /export/dfs/dn.txt
          • 将新机器的主机名放入写入该配置的文件
        • 执行刷新节点,namenode允许注册
        • 启动新机器的datanode
      • 如何不停机隔离机器
        • 将机器的地址写入该配置的文件中:dfs.hosts.exclude
        • 被指定的机器会变成decommissioning状态
    • -setQuota:限制某个目录下文件的个数

      #配置/wordcount这个目录下最多允许存放2个文件,如果设置为N,最大个数为N-1
      hdfs dfs -setQuota 3 /wordcount
      
    • -clrQuota:取消文件个数限制

      hdfs dfs -clrQuota /wordcount
      
    • -setSpaceQuota:设置该目录下最多允许存放的数据的大小

      • 这个值最小为:384M

      • 最小值 = 该目录下块的个数 * 3[副本]*128

      • 如果要存一个200M的文件:最小设置768才能存下

        • 2 * 3 * 128
          • block1:128M 128M
          • block2:72M 128M
        hdfs dfs -setSpaceQuota 768M /wordcount
        
    • -clrSpaceQuota:取消空间限制

      hdfs dfs -clrSpaceQuota /wordcount
      
  • haadmin

    • [-transitionToActive [–forceactive]]
      • 转换为active
      • serviceId:namenode的id
      • –forceactive:强制转换为【如果当前已经有active状态了,需要加上该参数进行强制转换】
    • [-transitionToStandby ]
      • 转为standby状态
    • [-failover [–forcefence][–forceactive] ]
      • 自动切换
    • [-getServiceState ]
      • 查看namenode的状态
  • fsck:检查文件系统 中是否有数据丢失或损坏,可以进行修复

    hdfs fsck /
    
  • balancer

    • IT行业中,有两种机制
      • 容灾机制:高可用【HA】,故障转移
      • 负载均衡:让每个节点的任务相对均衡,避免热点
    • 用于实现datanode之间的负载均衡:移动存储,让存储更均衡
    • 负载均衡的容差:10%
    • sbin/start-balancer.sh:只有发现出现热点以后再从
      • 占用大量的磁盘以及网络的IO,会导致整体的hdfs读写性能降低

JavaAPI(了解)

1、获取HDFS对象

    /**
     * 获取一个HDFS的对象
     */
    public FileSystem getHdfs() throws Exception {
        //构建一个Configuration对象,该对象是所有Hadoop程序都必须包含的对象,用于管理当前程序的所有配置
        //第一步该对象在程序启动时会加载所有的*-default.xml文件,读取所有默认配置,第二步加载所有*-site.xml文件,读取用户配置覆盖默认配置
        Configuration conf = new Configuration();
        //手动配置hdfs地址
        conf.set("fs.defaultFS","hdfs://node-01:8020");
        //构建hdfs对象
        FileSystem hdfs = FileSystem.get(conf);
//        FileSystem fs1 = FileSystem.get(new URI("hdfs://node-01:8020"), conf);
//        FileSystem fs2 = FileSystem.newInstance(new URI("hdfs://node-01:8020"), conf);
//        FileSystem fs3 = FileSystem.newInstance(conf);
        //返回HDFS对象
        return hdfs;
    }

2、打印集群信息

    /**
     * 获取集群的状态信息
     * @throws Exception
     */
    @Test
    public void getClusterInfo() throws Exception {
        //变成一个分布式文件系统对象
        DistributedFileSystem hdfs = (DistributedFileSystem) getHdfs();
        //获取所有datanode的状态
        DatanodeInfo[] dataNodeStats = hdfs.getDataNodeStats();
        //迭代打印每个datanode的信息
        for (DatanodeInfo dataNodeStat : dataNodeStats) {
            System.out.println(dataNodeStat.getDatanodeReport());
        }
    }

2、目录的创建

    /**
     * 在hdfs上创建一个目录
     */
    @Test
    public void createHdfsDir() throws Exception {
        FileSystem hdfs = getHdfs();
        Path path = new Path("/hdfsClient");
        //判断目录是否存在,如果存在,删除,重新创建
        if(hdfs.exists(path)){
            hdfs.delete(path,true);//如果是文件不需要递归,如果是目录需要递归
            hdfs.mkdirs(path);
        }else{
            hdfs.mkdirs(path);
        }
    }

3、文件的上传

    /**
     * 上传文件
     */
    @Test
    public void upLoadToHdfs() throws Exception {
        FileSystem hdfs = getHdfs();
        //上传文件
        Path inputPath = new Path("file:///C:\\output");//加file:///为了指定本地地址
        Path outputPath = new Path("/hdfsClient");
        hdfs.copyFromLocalFile(inputPath,outputPath);
        //关闭
        hdfs.close();
    }

4、文件的下载

    /**
     * 下载文件
     */
    @Test
    public void downLoadFromHdfs() throws Exception {
        FileSystem hdfs = getHdfs();
        Path inputPath = new Path("/wordcount/input/wordcount.txt");
        Path outputPath = new Path("file:///C:\\output\\count.txt");
        hdfs.copyToLocalFile(inputPath,outputPath);
        hdfs.close();
    }

5、目录及文件的列举

    /**
     * 列举
     * @throws Exception
     */
    @Test
    public void listHdfs() throws Exception {
        FileSystem hdfs = getHdfs();

        Path path = new Path("/");
/*
        //列举某个目录下的所有文件或者目录
        FileStatus[] fileStatuses = hdfs.listStatus(path);
        //迭代输出
        for (FileStatus fileStatus : fileStatuses) {
            //获取到每个文件的状态
            if(hdfs.isDirectory(fileStatus.getPath())){
                System.out.println(fileStatus.getPath() + "\t"+"这是一个目录");
            }else{
                System.out.println(fileStatus.getPath() + "\t"+"这是一个文件");
            }
        }
*/
        //列举某个目录下的所有文件,第二个参数表示是否递归
        RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = hdfs.listFiles(path, true);
        //不断迭代输出
        while(locatedFileStatusRemoteIterator.hasNext()){
            LocatedFileStatus next = locatedFileStatusRemoteIterator.next();
            System.out.println(next.getPath());
        }
    }

附录一:HDFS的Maven依赖

  • 添加模块依赖
    <!-- 指定仓库位置,依次为aliyun、cloudera和jboss仓库 -->
    <repositories>
        <repository>
            <id>aliyun</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
        <repository>
            <id>cloudera</id>
            <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
        </repository>
        <repository>
            <id>jboss</id>
            <url>http://repository.jboss.com/nexus/content/groups/public</url>
        </repository>
    </repositories>

    <properties>
        <hadoop.version>2.6.0-cdh5.14.0</hadoop.version>
    </properties>

    <dependencies>
        <!--引入单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- Hadoop Client 依赖 -->
		<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
		<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
    </dependencies>
  • 如果网络原因导致jar包无法下载,pom文件爆红,识别不了对应 的依赖
    • 改用Apache版本的依赖
      <properties>
      <hadoop.version>2.6.0</hadoop.version>
      </properties>
    
发布了3 篇原创文章 · 获赞 1 · 访问量 445

猜你喜欢

转载自blog.csdn.net/u013911970/article/details/103897083