[ hadoop ] HDFS架构

1 HDFS概述

1.1 简介

HDFS(Hadoop Distributed File System),它是一个文件系统

HDFS的使用场景:适合一次写入,多次读出的场景。

1.2 特点

优点:

  1. 大规模处理数据
  2. 多副本机制提高可靠性
  3. 高容错性:副本自动补全周期:6小时或集群重启

缺点:

  1. 不适合低延时数据访问,比如毫秒级的存储数据

    原因:结点间的数据访问涉及网络io,被带宽和距离,丢包(校验)等因素限制

  2. 无法高效的对大量小文件进行存储:

    1)小文件的元数据会占用nn大量内存

    2)存储的寻址时间>读取时间

  3. 不支持并发写入和随机修改:

    1)不允许多个线程同时写一个文件–>读读可并发;读写可并发;写(append)写不能并发;不可上传同一路径的同一文件

    2)仅支持数据append(追加),不支持文件的随机修改。

    随机修改:只能下载后修改再上传

1.3 组成架构

image-20220312125024923

nn(管理者):

  1. 管理HDFS的名称空间
  2. 配置副本策略
  3. 管理数据块映射信息
  4. 处理客户端读写请求

dn(执行者):

  1. 存储实际的数据块
  2. 执行数据块的读/写操作

2nn(辅助nn)

客户端:

发送读写请求,与nn和dn交互,上传(写)之前先将文件切块;

这里客户端不仅指发送指令的linux系统,windows环境下通过设置依赖亦可实现客户端环境,甚至在hdfs里nn的9870端口的web界面操作也可以对HDFS增删查

1.4 文件块大小

hdfs中文件在物理上分块(Block)存储:128M是hadoop2.x/3.x版本中的默认值

如何得到块大小:

寻址时间(找到block的时间)约10ms,其为传输时间的1/%时为最佳.

因此传输时间为1s,目前磁盘传输速率普遍100MB/s.所以块大小理论为100MB(按2进制)取整为128M

能否修改块大小且怎么修改合适?

  1. 块设置太小,相对地时间都耗费在寻址时间
  2. 块设置太大,程序处理这块数据时会非常慢
  3. 因此,HDFS块的大小设置取决于磁盘传输速率

2 HDFS的shell操作

hadoop fs 具体命令 或者 hdfs dfs 具体命令

2.1 命令大全

[atguigu@hadoop102 hadoop-3.1.3]$ bin/hadoop fs

        [-appendToFile <localsrc> ... <dst>]//追加一个文件到已经存在的文件末尾
        [-cat [-ignoreCrc] <src> ...]
        [-chgrp [-R] GROUP PATH...]
        [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
        [-chown [-R] [OWNER][:[GROUP]] PATH...]
        [-copyFromLocal [-f] [-p] <localsrc> ... <dst>]//从本地文件系统中拷贝文件到HDFS路径去,上传的同时可以改名
        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]//从HDFS拷贝到本地
        [-count [-q] <path> ...]
        [-cp [-f] [-p] <src> ... <dst>]
        [-df [-h] [<path> ...]]
        [-du [-s] [-h] <path> ...]
        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]//等同于copyToLocal,生产环境更习惯用get,下载也支持改名
        [-getmerge [-nl] <src> <localdst>]
        [-help [cmd ...]]
        [-ls [-d] [-h] [-R] [<path> ...]]
        [-mkdir [-p] <path> ...]//在hdfs创建文件夹
        [-moveFromLocal <localsrc> ... <dst>]//从本地剪切粘贴到HDFS
        [-moveToLocal <src> <localdst>]
        [-mv <src> ... <dst>]
        [-put [-f] [-p] <localsrc> ... <dst>]//等同于copyFromLocal,生产环境更习惯用put
        [-rm [-f] [-r|-R] [-skipTrash] <src> ...]
        [-rmdir [--ignore-fail-on-non-empty] <dir> ...]
<acl_spec> <path>]]
        [-setrep [-R] [-w] <rep> <path> ...]
        [-stat [format] <path> ...]
        [-tail [-f] <file>]
        [-test -[defsz] <path>]
        [-text [-ignoreCrc] <src> ...]

2.2 补充

常用命令包含:

  1. 4个上传命令(put,appendToFile),2个下载命令(get)

  2. -du 统计文件夹的大小信息 信息内容:文件大小 大小*副本数 绝对路径

  3. -setrep 设置HDFS中文件的副本数量

    这里设置的副本数只是记录在NameNode的元数据中

    只有3台设备,最多也就3个副本

    还得看DataNode的数量

    因此:副本数调整上限和集群扩容情况有关

3 HDFS的API操作

在准备客户端环境时主要步骤:

  1. 设置windows本地依赖,即配置hadoop环境变量
  2. Maven工程中导入hadoop客户端依赖
  3. 微软运行库安装

3.1 客户端类的编写

//客户端操作HDFS
public class HDFS_Demo {
    public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
        //hdfs通信端协议
        URI uri = new URI("hdfs://hadoop102:8020");

        //配置对象
        //加载配置文件,并读
        //加载Configuration类时,执行静态代码块,site配置文件覆写default文件,修改了默认值
        Configuration conf = new Configuration();

        String user = "zxk";//指定用户以使用该用户权限

        //如果不传uri参数则获取本地文件系统
        //FileSystem fs = FileSystem.get(conf);

        //org.apache.hadoop.hdfs.DistributedFileSystem分布式文件系统
        //通过反射使用配置文件conf创建文件系统
        FileSystem fs = FileSystem.get(uri, conf, user);

        fs.mkdirs(new Path("/java"));

        fs.close();//关闭客户端

    }
}

步骤说明:

  1. 提前创建hdfs通信端协议URI(选择8020通信端口,不是9870web端口)

  2. 创建配置类(Configuration)对象,加载配置文件,并读

    注意:加载Configuration类时,执行静态代码块,site配置文件覆写default文件,修改了默认值

  3. 指定用户以使用该用户权限

  4. 通过反射使用配置文件conf创建文件系统FileSystem

    说明:FileSystem是抽象类,调用构造方法时,传入的参数不同,获得的文件系统不同,具体为:

    1. 若传入协议和用户,则获得hdfs分布式文件系统org.apache.hadoop.hdfs.DistributedFileSystem

    2. 若只传入配置,则获得windows环境下的本地文件系统

      org.apache.hadoop.fs.RawLocalFileSystem

  5. 使用API

  6. 关闭客户端

3.2 测试参数优先级

前置工作:

  1. 将hdfs-site.xml拷贝到项目的resources资源目录下,文件中将副本参数设置为1

  2. 编写上传文件的源代码,在创建配置对象后,调用方法修改副本参数为2

    configuration.set(“dfs.replication”, “2”);

  3. 运行程序结果:hdfs中该文件的副本数为2

总结:

加载配置类时,静态代码块中可以看到,site配置文件中的内容会覆写default配置文件,而客户端代码中参数为最终结果,因此:

参数优先级:1xxx-default.xml服务器的默认配置<2xxx-site.xml服务器的自定义配置<3conf.set()客户端代码中设置的值

3.3 用io流上传和下载

以上传为例,步骤:

  1. 创建本地系统的流,new FileInputStream/FileOutputStream()

  2. 创建hdfs的流,fs.create(new Path())

  3. 流的对拷:IOUtils.copyBytes(本地流,hdfs流,conf)

    这里传入配置信息目的是提取一个参数–>缓冲大小(4096)

    可以直接将conf替换为4096

  4. 关流

4 HDFS读写流程

4.1 文件写入

4.1.1 流程

image-20220312164256677

第1步前置工作:客户端将文件切块Block,创建文件系统,按块逐个上传

第4步:按副本数选择节点数,存储节点选择机制:

​ 节点1:本地,即客户端所在的节点,如果本地负载过高,考虑负载均衡,就近选择第一个节点,另外:如果客户端在集群外,则随机选择第一个节点

​ 节点2:节点1的另一个机架的节点,这样可以保证副本的安全

​ 节点3:节点2所在机架的另一个节点(就近原则)

第5步:使用块传输通道(pipeline)的方式,优势在于可以保持丢包率的一直一致性

第7步:chunksum(4字节的校验和文件)包含:时间戳.元数据等信息

4.1.2 补充

  1. 使用同一个交换机的服务器构成机架,多个机架构成集群,多个集群构成数据中心

  2. 节点距离:两个节点到达最近的共同祖先的距离总和。

4.1.3 传输底层问题

问题1:当客户端不在dn节点上(比如windows),客户端如何确定上传成功?怎么确定是否丢包,以及怎么补救?

image-20220312171729841

确认回收机制:DataStreamer thread将包放进dataQueue发给管道第一个dn,然后从dataQueue移到ackQueue,处理器从dn收取ack.当收到所有节点的对应包的ack,处理器从ackQueue移除相应的包;如果没有收到ack,移除节点 的相关包(事务),重发

问题2:通道pipeline断开,通道上的某些节点不再传输怎么解决?

image-20220312172019642

当dn节点不工作,从ackQueue中移除所有未完成的数据包,先剔除坏掉的节点,建立新的传输通道,开始新的传输工作

4.2 文件读取

image-20220312173523597

5 NN和2NN

5.1 问题引出

  1. 为满足文件读写等过程中频繁访问元数据的需求,元数据需放在内存中,但安全性又得不到满足,因此需要备份元数据–>由此在磁盘中产生FsImage文件
  2. 内存中元数据更新,若FsImage随之更新,效率就会下降,而不更新,内存不保证安全性,导致数据丢失问题–>引入Edits文件(追加写,高效):将内存中更新的元数据追加写到Edits,这样通过合并FsImage和Edits得到完整的元数据
  3. 为保证合并效率,当Edits满足一定条件时,就会合并,这个工作就交给2nn,以此保证nn节点仍高效运行

5.2 工作机制

image-20220312180037710

说明:

  1. 2nn每1min就询问nn是否需要CheckPoint,以此检查正在写的Edits是否满了
  2. 合并条件:每1hour必须CheckPoint/Edits内容满100万/集群启动或重启时
  3. 如何查看到正在写的Edits:2nn和nn存放数据的目录中,文件只相差一个,就是正在写的Edits

思考:

问题1:通过oiv命令可以查看Fsimage文件中的内容,可以看出,Fsimage中没有记录块所对应DataNode,为什么?

可以看到,文件中记录了块的副本数和块的信息,而在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。–>每隔6小时自动上报块的位置,以此还能检验副本是否丢失,即上报的节点个数必须等于副本数–>若不满足副本数,则自动补全机制

问题2:NameNode如何确定下次开机启动的时候合并哪些Edits?

查看元数据存放的目录,看fsimage编号,fsimage_502存在,说明从edits_502以后开始合并

6 DN工作机制

image-20220312182939783

DataNode掉线时限,超时时长的计算公式为:

TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。

而默认的dfs.namenode.heartbeat.recheck-interval 大小为300000ms(5分钟),dfs.heartbeat.interval默认为3秒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值