Hadoop之HDFS

Posted 寒风孤月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hadoop之HDFS相关的知识,希望对你有一定的参考价值。

一.HDFS概述

1.1HDFS产生的背景定义


1)背景:随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的 操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
2)定义:HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭之后就不需要改变。

1.2 HDFS优缺点

1)优点:
1、可构建在廉价机器上
通过多个副本来提高可靠性,文件切分多个块进行存储
2、高容错性
数据自动保存多个副本,副本丢失后,可以自动恢复
3、适合批处理
移动计算比移动数据方便
4、适合大数据处理
10k+节点规模
5、流式文件访问
一次写入,多次读取,可以保证数据的一致性
2)缺点:
不适于以下操作
1、要求高的数据访问
比如毫秒级
2、小文件存取
寻道时间超过读取时间
3、并发写入、文件随机修改
一个文件只能有一个写
仅仅支持追加
4、不适合存储小文件
存储一个1亿个小文件,大小仅仅1t,但是消耗掉20g左右的内存

1.3HDFS组成架构

 **1.3.1架构介绍**

HDFS是一个主从(Master/Slaves)架构
由一个NameNode和一些DataNode组成
面向文件包含:文件数据(data)和文件元数据(metadata)
NameNode负责存储和管理文件元数据,并维护了一个层次型的文件目录树
DataNode负责存储文件数据(block块),并提供block的读写
DataNode与NameNode维持心跳,并汇报自己持有的block信息
Client和NameNode交互文件元数据和DataNode交互文件block数据

1.3.2角色功能
1) NameNode
完全基于内存存储文件元数据、目录结构、文件block的映射
需要持久化方案保证数据可靠性
提供副本放置策略
2)DataNode
基于本地磁盘存储block(文件的形式)
并保存block的校验和数据保证block的可靠性
与NameNode保持心跳,汇报block列表状态
3) Client:就是客户端。
文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;(2)与NameNode交互,获取文件的位置信息;
与DataNode交互,读取或者写入数据;
Client提供一些命令来管理IDFS,比INameNode格式化;
Client可以通过一些命令来访问HIDFS,比对HHDFSt增删查改操作;
4) Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
在非Ha模式下,SNN一般是独立的节点,周期完成对NN的EditLog向FsImage合并,减少EditLog大小,减少NN启动时间
根据配置文件设置的时间间隔fs.checkpoint.period 默认3600秒
根据配置文件设置edits log大小 fs.checkpoint.size 规定edits文件的最大值默认是64MB
1.3.3 HDFS文件块大小

举个例子:
100g的数据,集群有100个节点,按照1g的大小进行存储,每个节点要存储1g的数据量
100g的数据,集群有90个节点,按照1g的大小进行存储,其中有10台要存储2g的数据,其他的80台要存储1g的数据
假设1g的数据需要1秒钟的运算时间,那么整个任务需要2秒钟的运算时间。
100g的数据,集群有90个节点,按照512m的大小进行切分存储,有20个节点存储1.5g的数据,有70个节点存储1g的数据
假设1g的数据需要1秒钟的运算时间,那么整个任务需要1.5秒钟的运算时间。
从上面的这个例子结果来看,我们切分是不是越小越好?
但是有个问题:小文件很多,就会有问题!
举个例子:
access.log 100g
block0 50g
block1 50g
access.log 100g
block0 20g
block1 20g
block2 20g
block3 20g
block4 20g
从上面的这个例子结果来看:因为下载的时候需要将文件还原,需要合并块,从这看,是不是切分的越大越好?
不大不小:
HDFS在设计的时候考虑了不同的应用场景,每个不同的场景中,有可能需要的切分的块的大小不一样,可以配置。
HDFS集群块大小可以配置
但是有默认的大小:
Hadoop2.x版本以前,默认块大小:64M
Hadoop2.x版本及以后,默认块大小:128M

二.HDFS的Shell操作

2.1 基本语法
hadoop fs 具体命令 OR hdfs dfs 具体命令,两个是完全相同的。
2.2 命令大全

[wangzhao@hadoop102 ~]$ hadoop fs
Usage: hadoop fs [generic options]
	[-appendToFile <localsrc> ... <dst>]
	[-cat [-ignoreCrc] <src> ...]
	[-checksum <src> ...]
	[-chgrp [-R] GROUP PATH...]
	[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
	[-chown [-R] [OWNER][:[GROUP]] PATH...]
	[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
	[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
	[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
	[-createSnapshot <snapshotDir> [<snapshotName>]]
	[-deleteSnapshot <snapshotDir> <snapshotName>]
	[-df [-h] [<path> ...]]
	[-du [-s] [-h] [-v] [-x] <path> ...]
	[-expunge]
	[-find <path> ... <expression> ...]
	[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-getfacl [-R] <path>]
	[-getfattr [-R] -n name | -d [-e en] <path>]
	[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
	[-head <file>]
	[-help [cmd ...]]
	[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
	[-mkdir [-p] <path> ...]
	[-moveFromLocal <localsrc> ... <dst>]
	[-moveToLocal <src> <localdst>]
	[-mv <src> ... <dst>]
	[-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
	[-renameSnapshot <snapshotDir> <oldName> <newName>]
	[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
	[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
	[-setfacl [-R] [-b|-k -m|-x <acl_spec> <path>]|[--set <acl_spec> <path>]]
	[-setfattr -n name [-v value] | -x name <path>]
	[-setrep [-R] [-w] <rep> <path> ...]
	[-stat [format] <path> ...]
	[-tail [-f] [-s <sleep interval>] <file>]
	[-test -[defsz] <path>]
	[-text [-ignoreCrc] <src> ...]
	[-touch [-a] [-m] [-t TIMESTAMP ] [-c] <path> ...]
	[-touchz <path> ...]
	[-truncate [-w] <length> <path> ...]
	[-usage [cmd ...]]

Generic options supported are:
-conf <configuration file>        specify an application configuration file
-D <property=value>               define a value for a given property
-fs <file:///|hdfs://namenode:port> specify default filesystem URL to use, overrides 'fs.defaultFS' property from configurations.
-jt <local|resourcemanager:port>  specify a ResourceManager
-files <file1,...>                specify a comma-separated list of files to be copied to the map reduce cluster
-libjars <jar1,...>               specify a comma-separated list of jar files to be included in the classpath
-archives <archive1,...>          specify a comma-separated list of archives to be unarchived on the compute machines

The general command line syntax is:
command [genericOptions] [commandOptions]

2.3常用命令操作
1)-help:输出这个命令参数

[wangzhao@hadoop102 ~]$  hadoop fs -help rm
-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ... :
  Delete all files that match the specified file pattern. Equivalent to the Unix
  command "rm <src>"
                                                                                 
  -f          If the file does not exist, do not display a diagnostic message or 
              modify the exit status to reflect an error.                        
  -[rR]       Recursively deletes directories.                                   
  -skipTrash  option bypasses trash, if enabled, and immediately deletes <src>.  
  -safely     option requires safety confirmation, if enabled, requires          
              confirmation before deleting large directory with more than        
              <hadoop.shell.delete.limit.num.files> files. Delay is expected when
              walking over large directory recursively to count the number of    
              files to be deleted before the confirmation. 

2)创建/wz文件夹`

[wangzhao@hadoop102 ~]$ hadoop fs -mkdir /wz

3)上传

  1. -moveFromLocal:从本地剪切粘贴到HDFS
hadoop fs  -moveFromLocal  ./wz.txt  /wz
  1. -copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
hadoop fs -copyFromLocal wz.txt /wz

3)-put:等同于copyFromLocal,生产环境更习惯用put

hadoop fs -put ./wz.txt /wz
  1. -appendToFile:追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile wz.txt /wz/wz.txt

4)下载
1)-copyToLocal:从HDFS拷贝到本地

 hadoop fs -copyToLocal /wz/wz.txt ./
  1. -get:等同于copyToLocal,生产环境更习惯用get
hadoop fs -get /wz/wz.txt ./wz.txt

5)操作
1)-ls: 显示目录信息

 hadoop fs -ls /wz

2)-cat:显示文件内容

hadoop fs -cat /wz/wz.txt

3)-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限

hadoop fs  -chmod 777  /wz/wz.txt
hadoop fs  -chown  wangzhao:wangzhao   /wz/wz.txt

4)-rm:删除文件或文件夹

hadoop fs -rm /wz/wz.txt

5)-rm -r:递归删除目录及目录里面内容

hadoop fs -rm -r /wz

6)-mkdir:创建路径

hadoop fs -mkdir /wxh

7)从HDFS的一个路径拷贝到HDFS的另一个路径

hadoop fs -cp /wz/wz.txt  /jinguo

8)-mv:在HDFS目录中移动文件

hadoop fs -mv /wz/wy.txt /jinguo

三. HDFS的API操作

package com.wangzhao.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
/*
客户端代码常用套路
  1.获取客户端对象
  2.执行相关的操作
  3.关闭资源
  HDFS   Zookeeper
 */
public class HdfsClient 
    private FileSystem fs;
    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException 
        //链接集群nn的地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //创建一个配置文件
        Configuration conf = new Configuration();
        //用户
        String user ="wangzhao";

        //1.获取客户端对象
        fs = FileSystem.get(uri, conf,user);
    
    @After
    public void close() throws IOException 
        //3.关闭资源
        fs.close();
    

    //创建目录
    @Test
    public void testmkdir() throws  IOException 
        fs.mkdirs(new Path("/xiyou/huaguoshan1"));
    

    //上传
    /*
    参数优先级   hdfs-default.xml=>hdfs-site.xml=>在项目资源目录文件下的配置文件=》代码里面的配置
     */
    @Test
    public  void testPut() throws IOException 
        //参数一表示删除原数据 参数二 是否允许被覆盖   参数三 原数据路径  参数四目的地路径
        fs.copyFromLocalFile(true,false,new Path("D:\\\\sunwukong.txt"),new Path("/xiyou/huaguoshan"));
    
    //文件下载
    @Test
    public void testGet() throws IOException 
        // 参数一:原文件是否删除 参数二:原文件路径(HDFS) 参数三:目标地址路径(Win) 参数四:校验文件
        fs.copyToLocalFile(true,new Path("hdfs://hadoop102/xiyou/huaguoshan"),new Path("D:\\\\sunwukong.txt"),true);
    
    //删除
    @Test
    public void testRm() throws IOException 
        //参数一:要删除的路径 参数二:是否要递归删除
        //fs.delete(new Path("/xiyou/huaguoshan1/sunwukong.txt"),false);
        //删除空目录
        fs.delete(new Path("/xiyou/huaguoshan1"),false);
    
    //文件的更名和移动
    @Test
    public void testMv() throws IOException 
        //参数一原文件路径  参数二 目标文件的路径
        //对文件名称的修改
        //fs.rename(new Path("/xiyou/huaguoshan"),new Path("/xiyou/shuilian"));

        //文件的移动和更名
        fs.rename(new Path("/xiyou/shuilian"),new Path("/cls"));
    
    //获取文件详情
    @Test
    public void fileDetail() throws IOException 
        //获取所有文件信息
        RemoteIterator<LocatedFileStatus>  list_f = fs.listFiles(new Path("/"), true);
        while (list_f.hasNext())
            LocatedFileStatus  fileStatus = list_f.next();
            System.out.println("----------"+fileStatus.getPath()+"---------------");
            System.out.println(fileStatus.getPermission());
            System.out.println(fileStatus.getOwner());
            System.out.println(fileStatus.getLen());
            System.out.println(fileStatus.getModificationTime());
            System.out.println(fileStatus.getReplication());
            System.out.println(fileStatus.getBlockSize());
            System.out.println(fileStatus.getPath().getName());
            //获取块信息
            System.out.println("获取块信息");
            BlockLocation[] locations = fileStatus.getBlockLocations();
            System.out.println(Arrays.toString(locations));
        
    
    //判断是文件还是文件夹
    @Test
    public void testFile() throws IOException 
        FileStatus[] list = fs.listStatus(new Path("/"));
        for (FileStatus status : list) 
            if (status.isFile()) 
                System.out.println("     文件 :    "+status.getPath().getName());
            else 
                System.out.println("目录:"+status.getPath().getName());
            
        
    

四.HDFS读写流程(重点)

1)Block的副本放置策略
第一个副本:放置在上传文件的DN;如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。
第二个副本:放置在于第一个副本不同的 机架的节点上。
第三个副本:与第二个副本相同机架的节点。
更多副本:随机节点。
2)写流程

Client和NN连接创建文件元数据
NN判定元数据是否有效
NN处发副本放置策略,返回一个有序的DN列表
Client和DN建立Pipeline连接
Client将块切分成packet(64KB),并使用chunk(512B)+chucksum(4B)填充
Client将packet放入发送队列dataqueue中,并向第一个DN发送
第一个DN收到packet后本地保存并发送给第二个DN
第二个DN收到packet后本地保存并发送给第三个DN
这一个过程中,上游节点同时发送下一个packet
生活中类比工厂的流水线
Hdfs使用这种传输方式,副本数对于client是透明的
当block传输完成,DN们各自向NN汇报,同时client继续传输下一个block
所以,client的传输和block的汇报也是并行的
3)读流程

为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。
如果在读取程序的同一个机架上有一个副本,那么就读取该副本。
如果一个HDFS集群跨越多个数据中心,那么客户端也将首先读本地数据中心的副本。
语义:下载一个文件:
Client和NN交互文件元数据获取fileBlockLocation
NN会按距离策略排序返回
Client

以上是关于Hadoop之HDFS的主要内容,如果未能解决你的问题,请参考以下文章

Hadoop HDFS编程 API入门系列之从本地上传文件到HDFS

Hadoop HDFS编程 API入门系列之路径过滤上传多个文件到HDFS

Hadoop HDFS编程 API入门系列之HdfsUtil版本1

Hadoop 核心编程之 HDFS 的文件操作

Hadoop 核心编程之 HDFS 的文件操作

Hadoop 核心编程之 HDFS 的文件操作