二, 大数据基础架构Hadoop-HDFS入门和基本操作(基本组成, Shell操作, API操作, 读写流程) hf

一, HDFS概述

1.1 HDFS的产生背景和定义

  1. 随着数据量越来越大,我们需要把文件分布存储到多台计算机上,分布式文件管理系统作为一种管理多台机器上文件的系统应运而生, HDFS是其中的一种.
  2. HDFS定义:
    • Hadoop Distributed File System,
    • 通过目录树来定位文件
    • 分布式的. 很多服务器联合起来实现功能,集群中的服务器有各自的角色.
    • 使用场景: 适合一次写入,多次读取的场景. 一个文件经过创建,写入和关闭后就不需要改变

1.2, HDFS的优缺点:

  • 优点:
  • 高容错性(多个副本, 自动恢复). 数据自动保存多个副本,通过增加副本的形式,提高容错性. 某一个副本丢失,它可以自动恢复.
  • 适合处理大数据(超大文件). GB,TB甚至于PB级别的数据或者是百万规模以上的文件数量.
  • 可构建在廉价机器上. 通过多副本机制,提高可靠性.
  • 缺点:
  • 不适合低延时数据访问. 比如毫秒级的存储数据,是做不到的, HDFS是为高数据吞吐量应用优化的, 这可能会以提高时间延迟为代价, 目前来说, 对于低延迟的访问需求, HBase是更好的选择.
  • 无法高效的对大量小文件进行存储.
    1. 存储大量小文件的话,它会占用NameNode大量的内存来存储文件系统的元数据. 由于NameNode的内存总是有限的,所以不可取.
    2. 小文件存储的寻址时间会超过读取时间,他违反了HDFS的设计目标.
  • 不支持并发(多个用户)写入,也不支持在文件的任意位置进行修改
    1. 一个文件只允许一个用户写,不允许多个用户同时写
    2. 仅支持数据追加(append)到文件末尾, 不支持文件的随机修改.

1.3, HDFS组成架构

  1. NameNode(nn),即master,他是一个管理者.
  • NameNode 执行的操作 主要分为三类, 如下表所示:
类别 说明
1. 维护管理HDFS的命名空间 维护整个文件系统的目录树, 文件/目录的元数据信息和文件的数据块索引(每个文件对应的数据块列表). 这些信息在NameNode中保存在两个文件中, 分别是 FSImame(文件系统镜像)和 Edits(编辑日志)
2. 确定数据块-DataNode的映射关系 client读取数据先访问NameNode, 由NN获取数据所在的DN, 然后client读取目标DN得到数据. 注意: 数据块-DataNode的映射关系是由NameNode根据DataNode上报的文件块信息动态重建的而不是持久化保存,从而减轻了NameNode的负担
3. 管理DataNode结点的状态报告 包括DataNode的健康状态报道和其所在结点上数据块的状态报告, 以便能够及时处理失效的DataNode

注意:

  1. FSImage-文件系统镜像, 在NameNode启动时对整个文件系统的快照;
  2. edits-编辑日志, 在NameNode启动之后, 记录对文件系统的改动序列;
  1. DataNode,即Slave,NameNode下达命令.DataNode执行实际的操作, 如下表所示:
类别 说明
1. 负责实际执行自身结点上数据的读写和存储 一般是文件系统客户端需要请求对NN指定的DataNode结点进行读写操作, DataNode作为数据结点的服务进程与文件系统打交道.
2. 定期向NameNode报告状态 每个DataNode会周期性地向NameNode发送心跳信号和文件块报告(心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用)
3. 执行数据的流水线复制 当文件系统客户端从NameNode服务器进程获取到要进行复制的数据块列表后, 由DataNode完成文件块和块副本的流水线复制
  1. Client,客户端

    • 文件切分.文件上传HDFS的时候,Client将文件切分为一个个的Block,然后进行上传;
    • 与NameNode交互,获取文件的位置信息;
    • 与DataNode交互,读取或写入数据;
    • Client提供一些命令来管理HDFS,比如NameNode格式化;
    • Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作.
  2. Secondary NameNode: 并非NameNode的热备份,当NameNode挂掉后,并不会马上替换NameNode并提供服务

    • 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给Namenode(保持一个较新的文件系统快照);
    • 在紧急情况下,可辅助恢复NameNode.

    对2NN的详细说明

1.4 HDFS文件块大小(面试重点)

HDFS中的文件在物理上是分块存储的(Block),块的大小可以通过配置参数(hdfs-default.xml文件中的dfs.blocksize)来规定, 默认大小在Hadoop2.x/3.x版本中是128M, 1.x版本中是64M.

Q: 为什么块的大小不能设置太小,也不能设置太大?

  1. HDFS块的大小设置主要取决于磁盘传输速率;
  2. HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置;
  3. 如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间. 导致程序在处理这块数据时, 会非常.
  • 总结: HDFS的块大小主要取决于磁盘传输速率。

二, HDFS的Shell操作

2.1 HDFS的常用命令

  • 格式:
    hadoop fs 具体命令 OR hdfs dfs 具体命令

2.2, 上传文件

  1. 先在HDFS创建一个测试文件夹

hdfs dfs -mkdir shellTest
注意: 不要忘记带路径符号正斜杠, ‘/’

在这里插入图片描述

  1. 本地剪切文件到HDFS

-moveFromLocal ./文件名 /目标目录 (命令大小写严格区分噢, movefromlocal就不对)

示例:
在这里插入图片描述
进入HDFS web管理页面(bigdata01:9870), 点击可以查看目录和文件
在这里插入图片描述

  1. 本地上传文件到HDFS

-put ./文件名 /目标目录
或者是, -copyFromLocal ./文件名 /目标目录名


在这里插入图片描述

  1. 追加文件到另一个已经存在文件的末尾

-appendToFile ./文件名 /目录名/文件名

举个栗子:

在本地新建一个cal.txt, 然后把cal指令(显示本月日历)结果追加到cal.txt(其实追加命令自己可以新建文件哈), 之后在hdfs中-touch新建一个time.txt, cal.txt追加到hdfs的/shellTest/time.txt中, 并-cat打印输出结果.
在这里插入图片描述

2.3, 下载文件

  1. 从HDFS下载文件到本地

-get /目录/文件 ./
或者是, -copyToLocal /目录名/文件名

示例:

在这里插入图片描述

  • 如果你下载文件同时并改个名,

在这里插入图片描述

2.4, 常用Shell命令

  1. -ls 查指定路径文件和目录的详细信息

    注意: HDFS的 -ls 操作等用于于的是 linux 的 ll操作

    在这里插入图片描述

  2. -cat 打印输出文件内容
    在这里插入图片描述

  3. -chmod(-chgrp -chown) 修改文件所属权限
    在这里插入图片描述
    在这里插入图片描述

  4. -mkdir 创建目录
    在这里插入图片描述

  5. -cp, -mv 复制,移动文件;从HDFS的一个路径到另一个路径
    在这里插入图片描述

  6. -rm 删除文件或目录(-rm -r)
    在这里插入图片描述

  7. -tail 显示一个文件的末尾的1kb的数据
    在这里插入图片描述

Q: 为什么要查看末尾? 因为末尾的文件内容随着追加操作不断更新,时效性较强.比如.日志文件.

  1. -du 统计文件夹的大小信息 ( -du -s 汇总加和, -h 以人类易读的方式显示)
    在这里插入图片描述

第一列是文件的大小,第二列除以第一列的值是文件的副本数量;

如shuguo.txt这个文件大小是7B, 有14/7=2个副本;

-du -h -s 是文件夹的所有文件的信息
-du -h 是文件夹的总体信息

  1. -setrep (replication)设置HDFS中文件的副本数量
    在这里插入图片描述
    在这里插入图片描述
  • 实际还是只有三个副本, 因为目前只有这三台DataNode节点
    在这里插入图片描述

这里设置的副本数只是记录在NameNode 的元数据中,是否真的会有这么多副本,还得看DataNode的数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到8台时,副本数才能达到8。
!!! 一台机器一个副本,多了没意义!

三, 基于JAVA的HDFS的API操作

参见此文: 二-0, 大数据基础架构Haoop- 在Windows客户机上对HDFS的API操作

四, HDFS的读写流程(面试重点)

4.1, HDFS写数据流程

4.1.1 HDFS文件写入剖析(需要进一步深入)

具体步骤:

  1. 客户端通过 DistributedFileSystem模块向NameNode请求上传文件,NameNode检查目录结构(检查目标文件是否存在,父目录是否存在,权限是否满足);
  2. NameNode返回请求是否可以上传;
  3. 客户端对待传文件进行切分,分为若干个block (每个block的大小为64M 或者 128M),然后向NameNode请求上传第一个Block到哪几个DataNode服务器上;
  4. NameNode考虑每一个节点是否可用, 节点距离最近, 负载均衡等因素返回3个DataNode节点,分别为dn1,dn2,dn3;
  5. 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求后会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成;
  6. dn1,dn2,dn3逐级应答客户端;
  7. 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(大小为64k, 由多个chunk512字节+chunkSum4字节组成),dn1收到一个Packet就会传给dn2,dn2传给dn3; dn1每传一个packet会放入一个应答队列等待应答();
  8. 当一个Block传输完成之后,客户端再次请求NameNode上传第二个BLock的的服务器(重复执行3-7步).

待参考的文章
待参考文章2

4.1.2 网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择离上传数据最近距离的DataNode接收数据,那么这个最近距离是如何计算的呢?
节点距离: 两个节点到达最近的共同祖先的距离总和( 什么是共同祖先, 比如一个机架中两个结点的共同祖先就是这个机架; ab两个机架中的两个节点的共同祖先就是ab两个机架构成的集群)

示例:

4.1.3 机架感知(副本存储节点选择)

选择策略(假如集群有三个副本)

  1. 第一个副本在Client所处的节点上,如果客户端在集群外,随机选一个;(节点越近,上传速率越快)
  2. 第二个副本在另一个机架的随机一个节点上;(保证数据的可靠性)
  3. 第三个副本在第二个副本所在机架的随机节点;(同时兼顾效率)

三个副本的机架感知概括如下: 跟Client同机架的其他一个节点, 别的机架A上的一个节点, 别的机架A上一个随机节点.

4.2, HDFS 读数据流程

具体步骤:

  1. 客户端通过 DistributedFileSystem 向 Namenode请求下载文件, NameNode通过查询元数据,找到文件块所在的DataNode地址;
  2. 挑选一台DataNode(节点最近,负载均衡 )服务器,请求读取数据;
  3. DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验);
  4. 客户端以Packet为 单位接收,先在本地缓存,然后写入目标文件;

五, NameNode和Secondary NameNode

5.1, NN和2NN工作机制-引言

首先思考一个问题: NameNode中的元数据是存储在哪里的?

  1. 如果把元数据存放在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,所以必然会效率过低; 因此我们要把元数据存放到内存中.
  2. 但是,如果元数据只存在内存中,一旦断电,元数据丢失,整个集群就完犊子了, 所以我们引出了在磁盘中备份元数据,叫FsImage;
  3. 然而新问题又来了,当在内存中的元数据更新时,如果同时去更新FsImage,又会导致效率过低, 但是不更新的话又会发生一致性问题, 一旦NameNode断电,数据又丢了个鸡儿的.因此我们引入了 Edits文件(只进行追加操作,效率很高),每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中.这样, 一旦NameNode节点断电,可以通过FsImage和Edits的合并,合并出当时的元数据.
  4. 但是! 如果长时间添加数据到Edits中而不及时合并,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长.因此, 需要定期进行FsImage和Edits的合并, 如果这个操作由NameNode节点完成,又会导致效率过低,所以,我们又引入了一个新的节点Secondary NameNode, 专门用于FsImage和Edits的合并.

Fsimage 在磁盘中备份元数据;
Edits 记录对数据发生的修改;
Secondary NameNode定时合并上面两个文件;

参见此文: Secondary NameNode:它究竟有什么作用?

5.2, NN和2NN工作机制-详述

在这里插入图片描述

  1. 第一阶段: NameNode启动

    1. 第一次启动NameNode格式化后,创建Fsimage和Edits文件.如果不是第一次启动,则直接加载编辑日志和镜像文件到内存;
    2. 客户端对元数据进行增删改的请求;
    3. NameNode记录操作日志,更新滚动日志(记录到edits_inprogress);
    4. NameNode在内存中对元数据进行增删改;
  2. 第二阶段: Secondary NameNode工作

    1. Secondary NameNode询问NameNode是否需要CheckPoint. 直接带回NameNode是否检查结果;
    2. Secondary NameNode 执行CheckPoint;
    3. NameNode 滚动正在写的Edits日志;
    4. 滚动前的编辑日志(Edits)和镜像文件(fsimage)拷贝到 Secondary NameNode;
    5. Secondary NameNode加载编辑日志和镜像文件到内存,并进行合并;
    6. 生成新的镜像文件 fsimage.chkpoint;
    7. 拷贝fsimage.chkpoint回到NameNode;
    8. NameNode将fsimage.chkpoint重新命名为 fsimage,覆盖原来的fsimage.

checkpoint的触发条件:

  1. 定时时间到
  2. Edit中的数据满了

5.3, Fsimage和Edits文件的解析

NameNode 被格式化以后,将在/hadoop安装目录/data/tmp/dfs/name/current 目录下产生如下文件:
在这里插入图片描述

  1. fsimage文件: HDFS文件系统元数据的一个永久的检查点,其中包含HDFS文件系统的所有目录和inode的序列化信息;
  2. edits文件: 存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中;

每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据是最新的,同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并.

  1. seen_txid文件: 保存的是一个数字,就是最后一个edits_的数字;
    在这里插入图片描述
  2. VERSION文件: 记录 NameNode节点对应的命名空间的id, HDFS 集群的唯一标识符cluster_id(这些标识符与DataNode一致, 用于防止 DataNode 意外注册到属于不同集群的不正确 NameNode。)

5.3.1, 使用oiv命令查看 fsimage文件

  1. oivoev

  2. 基本语法:

    hdfs oiv -p 文件类型 -i镜像文件 -o\转换后文件输出路径   
  1. 案例实操:
    在这里插入图片描述
  • 我们在xshell中使用 sz fsimage把该文件下载到本地, 用BowPad打开查看, 比如 我们要查看hdfs中/user/win10/abb.txt的目录信息:
    在这里插入图片描述
  • 我们可以在其中的一个BLOCK中查找到这些文件或目录名.
    在这里插入图片描述
  • 在fsimage靠后的位置存储着, 上面文件和目录的parent-child 归属关系
    在这里插入图片描述

通过查看fsimage我们可以清楚的知道, NN只负责记录文件的元数据信息, 并不知道文件的具体存储位置, 而是由DN负责告知的.

5.3.2, 使用oev查看Edits文件

  1. 基本语法
hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径  
  1. 案例实操
  • 我们先对HDFS执行一次操作, 这里我随便上传一个文件到HDFS中.
    在这里插入图片描述
  • 提取日志文件到Windows中, 用BowPad打开.

在这里插入图片描述

  • 下面是我在操作HDFS上传文件后, edits中的记录
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EDITS>
  <EDITS_VERSION>-64</EDITS_VERSION>
  <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>1197</TXID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>1198</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16614</INODEID>
      <PATH>/apiTest/text.txt._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1625197340573</MTIME>
      <ATIME>1625197340573</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME>DFSClient_NONMAPREDUCE_947767106_1</CLIENT_NAME>
      <CLIENT_MACHINE>192.168.182.100</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>win10</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <ERASURE_CODING_POLICY_ID>0</ERASURE_CODING_POLICY_ID>
      <RPC_CLIENTID>6b6c7166-b01f-42bd-a859-d5963b730497</RPC_CLIENTID>
      <RPC_CALLID>3</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>1199</TXID>
      <BLOCK_ID>1073741964</BLOCK_ID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
    <DATA>
      <TXID>1200</TXID>
      <GENSTAMPV2>1140</GENSTAMPV2>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD_BLOCK</OPCODE>
    <DATA>
      <TXID>1201</TXID>
      <PATH>/apiTest/text.txt._COPYING_</PATH>
      <BLOCK>
        <BLOCK_ID>1073741964</BLOCK_ID>
        <NUM_BYTES>0</NUM_BYTES>
        <GENSTAMP>1140</GENSTAMP>
      </BLOCK>
      <RPC_CLIENTID/>
      <RPC_CALLID>-2</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_CLOSE</OPCODE>
    <DATA>
      <TXID>1202</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/apiTest/text.txt._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1625197342135</MTIME>
      <ATIME>1625197340573</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME/>
      <CLIENT_MACHINE/>
      <OVERWRITE>false</OVERWRITE>
      <BLOCK>
        <BLOCK_ID>1073741964</BLOCK_ID>
        <NUM_BYTES>21359</NUM_BYTES>
        <GENSTAMP>1140</GENSTAMP>
      </BLOCK>
      <PERMISSION_STATUS>
        <USERNAME>win10</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_RENAME_OLD</OPCODE>
    <DATA>
      <TXID>1203</TXID>
      <LENGTH>0</LENGTH>
      <SRC>/apiTest/text.txt._COPYING_</SRC>
      <DST>/apiTest/text.txt</DST>
      <TIMESTAMP>1625197342157</TIMESTAMP>
      <RPC_CLIENTID>6b6c7166-b01f-42bd-a859-d5963b730497</RPC_CLIENTID>
      <RPC_CALLID>8</RPC_CALLID>
    </DATA>
  </RECORD>
</EDITS>

Q-A:

  1. NameNode如何确定下次集群启动时合并哪些信息?
    • 当前的 fsImage文件我们是已知的, fsImage的文件名也是已知的, 所以只需合并edits文件名中的序号大于 fsImage文件名序号的部分 edits文件即可.
  2. NN 和 2NN的差异文件?
    • edits-inprogress
      在这里插入图片描述

5.4, CheckPoint时间设置

  1. 定时通常情况下,Secondary NameNode 每隔一小时执行一次
    在这里插入图片描述

  2. 定次数一分钟检查一次操作次数,当操作次数达到一百万时,SecondaryNameNode执行一次;

在这里插入图片描述

六, DataNode

6.1, DataNode工作机制


在这里插入图片描述

  1. 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件, 一个是数据本身, 另一个是元数据(.meta文件)(包括数据块的长度,块数据的校验和,以及时间戳);
  2. DataNode启动后向NameNode注册(报告块信息),NN返回注册成功的消息. 为避免中途宕机, DataNode会周期性(6小时)的向NameNode上传所有的块信息;
  3. 心跳(告诉NN本DN还活着)是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令比如复制块数据到另一台机器,或是删除某个数据块. 如果超过十分钟没有收到某个DataNode的心跳(10分钟+ 30秒, 即十分钟再加上十次心跳),则认为该节点不可用;
  4. 集群运行中可以安全加入和退出一些机器.

6.2, 数据完整性

  • DataNode节点保证数据完整性的方法:
    1. 当DataNode读取Block的时候,它会计算CheckSum;
    2. 如果计算后的CheckSum, 与Block创建时值不一样,说明Block已经损坏;
    3. Client读取其他DataNode上的Block;
    4. 常见的校验算法 crc(32), md5, sha1;
    5. DataNode在其文件创建后周期验证ChechSum;

6.3 掉线时限参数设置

10分钟 + 30s

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

猜你喜欢

转载自blog.csdn.net/nmsLLCSDN/article/details/118304926