Hadoop-HDFS基础

一、Hadoop简介

1、Hadoop是什么

  • Hadoop是一个由Apache基金会所开发的分布式系统基础框架
  • 主要解决了海量数据的存储(HDFS)和海量数据的分析计算(MapReduce)问题
  • 广义来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈。如图:

Hadoop生态圈

2、Hadoop的特点

  • 高可靠性 :Hadoop底层将数据以多个副本的形式存储在不同的机器上,保证数据的安全可靠。
  • 高扩展性 :当存储hdp集群的存储能力和运算资源不足时,可以横向的扩展机器节点来达到扩容和增强运算能力 。
  • 高效性 :在MapReduce的思想下能够在节点之间动态地移动运算,且是分布式并行工作的,所以运算海量数据非常高效。
  • 高容错性 : Hadoop能够自动保存数据的多个副本,当有存储数据的节点宕机以后, 会自动的复制副本维持集群中副本的个数 ,并且能够自动将失败的任务重新分配。
  • 低成本 :hadoop可以运行在廉价的机器上并行工作,达到高效,安全,效率于一身目的。

3、Hadoop的组成

Hadoop的组成

  • HDFS:(Hadoop Distribute File System)分布式文件系统,海量数据存储解决方案
  • MapReduce:Hadoop的分布式运算编程框架(并行运算)
  • Yarn:分布式资源调度平台和任务监控平台
  • Commons: HADOOP底层技术支持

二、HDFS

1、HDFS简介

HDFS(Hadoop Distribute File System ):分布式文件系统,解决了海量数据无法单台机器存储的问题,将海量的数据存储在不同的机器中 ,由HDFS文件系统统一管理和维护, 提供统一的访问目录和API !

2、HDFS优缺点

(1)优点:

  • 高容错性,安全性
    数据存储在不同的机器中,并且每个数据块默认存储3个副本(存储在不同的机器中),当集群中的某个数据块的副本由于某种原因(宕机,磁盘损坏等)丢失以后,HDFS会自动恢复!
  • 扩展性
    HDFS的存储能力可以通过添加机器来扩容,并且极易横向扩容 ,整个集群中所有机器的存储能力就是HDFS的存储能力
  • 可以存储海量数据
    单个很大的文件可以存储在HDFS中,也可以存储百万个以上的文件数据量

(2)缺点:

  • 不适合低延迟的数据访问 , 比如毫秒级的数据访问和数据存储
    数据底层存储在不同的机器中, 并且大文件会被切块存储在不同的机器中, 读取数据极可能需要RPC远程网络请求获取数据 ,所以数据的访问时间比较长
  • 不适合存储大量的小文件数据
    每个数据文件在namenode中记录元数据信息,存储大量小文件增加namenode的压力,占用NN(即namenode)的内存,影响集群的整体存储能力!
    大量小文件的寻址时间会超过读取时间(读取时间/寻址时间=100/1)
  • 不支持并发写, 文件的随机修改
    一个文件仅支持单个线程写 , 不支持多个线程写
    仅支持数据的append(追加)操作 ,不支持数据的随机写
  • 单节点故障 :过于依赖主节点

注意:HDFS文件系统适合一次写入多次读取的数据操作!主要用于存储数据!

3、HDFS组成架构

HDFS采用的是主从结构模式 , 主节点[MASTER]namenode,从节点[SLAVES]datanode
HDFS原理图
HDFS 采用Master/Slave的架构来存储数据,这种架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary NameNode

  • 1、Client:就是客户端
    (1)文件切分。文件上传 HDFS 的时候,Client 将文件切分成一个一个的Block(数据块),然后进行存储。
    (2)与 NameNode 交互,获取文件的位置信息。
    (3)与 DataNode 交互,读取或者写入数据。
    (4)Client 提供一些命令来管理 HDFS,比如启动或者关闭HDFS。
    (5)Client 可以通过一些命令来访问 HDFS。
  • 2、NameNode:就是 master,它是一个主管、管理者
    (1)用于记录文件存储的元数据信息(NameNode将这些数据的元数据信息记录在内存中,并且将这些元数据信息定期的序列化到本地磁盘上), 记录用户操作的行为日志,记录用户存储的文件的大小、切分的块数、每一块的副本数和存储在DataNode上的位置
    (2)接收客户端的请求,给datanode分配存储任务 , 或者是返回给客户端请求数据的元信息
    (3)维护集群中的节点的数量,接收datanode的注册, 维护了一个统一的集群版本
    (4)维护集群中数据的负载均衡和副本个数
    (5)接收datanode的心跳汇报
    (6)接收datanode的数据的汇报 , 更新节点映射(更新元数据信息)
  • 3、DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作
    (1)存储数据,将数据以物理切块的形式存储在本地指定的磁盘目录中
    (2)处理客户端的请求
    (3)接收namenode 分配的任务
    (4)接收namenode的指令完成容错工作 , 副本的复制 移动
    (5)定期的向namenode心跳响应请求,默认每间隔3s一次
    (6)汇报自己存储的数据数据1h
  • 4、Secondary NameNode:并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务
    (1)辅助 NameNode,分担其工作量。
    (2)定期合并 fsimage和fsedits,并推送给NameNode。
    (3)在紧急情况下,可辅助恢复 NameNode。

4、HDFS的读写流程

(一) HDFS写数据流程

HDFS写数据流程

(1)剖析文件写入
  • (1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。

  • (2)NameNode返回是否可以上传。

  • (3)客户端请求第一个 Block上传到哪几个DataNode服务器上。

  • (4)NameNode返回3个DataNode节点(跟设置的副本策略有关系,设置几个,就返回几个DN),分别为dn1、dn2、dn3。

  • (5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个 pipeline 通信管道建立完成。

  • (6)dn3应答->dn2应答->dn1->应答客户端(逐级应答,dn1会包含dn2和dn3的应答结果)。

  • (7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(64kb),dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。

  • (8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。

(2)网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。
在这里插入图片描述
在同一节点上,它们之间的距离当然是0,2*0=0
在同一机架上的不同节点,它们的共同祖先就是这个机架,而这两个节点到机架的距离都是1,所以这两个节点的距离为1+1=2
在同一集群的不同机架上的节点,它们的共同祖先是集群,而这两个节点要到达集群,首先要到这个机架(距离1),然后到达集群(距离2),所以两个节点的距离为2+2=4
在同一数据中心的不同集群上的节点,它们的共同祖先是数据中心,以此类推,一个节点到数据中心的距离是3,两个节点的距离就是3+3=6

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

在这里插入图片描述

(二) HDFS读数据流程

在这里插入图片描述

  • (1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。

  • (2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。

  • (3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。

  • (4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。

注意:1、同一个文件的几个block可以再不同的DataNode上。2、读文件只能按顺序读,并且只能一个一个读,不能并行。

(三)hdfs 数据流单位 block、packet与chunk

在DFSClient写HDFS的过程中,有三个需要搞清楚的单位:block、packet与chunk;

  • block是最大的一个单位,它是最终存储于DataNode上的数据粒度,由dfs.block.size参数决定,默认大小在hadoop2.x版本中是128M,老版本中是64M;注:这个参数由客户端配置决定;

  • packet是中等的一个单位,它是数据由DFSClient流向DataNode的粒度,以dfs.write.packet.size参数为参考值,默认是64K;
    注:这个参数为参考值,是指真正在进行数据传输时,会以它为基准进行调整,调整的原因是一个packet有特定的结构,调整的目标是这个packet的大小刚好包含结构中的所有成员,同时也保证写到DataNode后当前block的大小不超过设定值;

  • chunk是最小的一个单位,它是DFSClient到DataNode数据传输中进行数据校验的粒度,由io.bytes.per.checksum参数决定,默认是512B;

写过程中的三层buffer

写过程中会以chunk、packet及packet queue三个粒度做三层缓存;

  • 首先,当数据流入DFSOutputStream时,DFSOutputStream内会有一个chunk大小的buf,当数据写满这个buf(或遇到强制flush),会计算checksum值,然后填塞进packet;

  • 当一个chunk填塞进入packet后,仍然不会立即发送,而是累积到一个packet填满后,将这个packet放入dataqueue队列;

  • 进入dataqueue队列的packet会被另一线程按序取出发送到datanode;

(注:生产者消费者模型,阻塞生产者的条件是dataqueue与ackqueue之和超过一个block的packet上限)

在这里插入图片描述

5、HDFS文件块大小

HDFS文件块大小

  • HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M。
  • 如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小设置约为100MB。默认的块大小128MB。
  • 块的大小:10ms*100*100M/s = 100M
  • HDFS的块设的太小,会增加寻址时间,程序一直在找块的开始时间
  • 如果块设置得太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间导致程序在处理这块数据时,会非常慢。
  • 传输一个由多个块组成的文件的时间取决于磁盘传输速率,HDFS块的大小设置也主要取决于磁盘传输速率

设置块大小:

设置 hdfs-site.xml 下面的属性值

<property>
    <name>dfs.block.size</name>
    <value>134217728</value>    <-- 设置为128M -->
    <description>Block size</description>
</property>

修改说明:

hdfs-site.xml 是HDFS的配置文件,修改 hdfs-site.xml 配置文件的 dfs.block.size 属性值就会改变上传到HDFS所有文件的默认块大小。修改这个值并不会对HDFS上现存的任何文件的块大小产生影响,只会改变新上传文件的块大小。

6、NameNode详解

(1)NN和2NN工作机制(NameNode与Secondary NameNode)

思考:NameNode中的元数据是存储在哪里的?

首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage

这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高),每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中 。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据

但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并
NN和2NN工作机制
NN和2NN工作机制详解:

(1)第一阶段:NameNode启动

  • 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,先滚动Edits并生成一个空的edits.inprogress,然后加载编辑日志(Edits)和镜像文件(Fsimage)到内存中,执行Edits文件中的更新操作,保证内存中的元数据信息是最新的、同步的(可以看成NameNode启动时将Fsimage和Edits进行了合并)。
  • 客户端对元数据进行增删改的请求。
  • NameNode 先在日志中记录操作(只在最后追加,不修改),更新滚动日志。(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息)
  • NameNode 然后再在内存中对元数据进行增删改。
  • 如果此时NameNode挂掉,重启后会从Edits中读取元数据的信息。然后,NameNode会在内存中执行元数据的增删改的操作

(2)第二阶段:Secondary NameNode工作

  • Secondary NameNode 询问 NameNode 是否需要CheckPoint。直接带回NameNode是否检查结果。(触发CheckPoint需要满足两个条件中的任意一个,定时时间到了和Edits中数据写满了。SecondaryNameNode 默认每隔一小时执行一次)
  • Secondary NameNode请求执行CheckPoint。
  • NameNode 滚动正在写的Edits日志并生成一个空的edits.inprogress。滚动Edits的目的是给Edits打个标记,以后所有新的操作都写入edits.inprogres
  • 将未合并的编辑日志(Edits)和 镜像文件(fsimage)下载到Secondary NameNode。(HTTP GET方式)
  • Secondary NameNode加载编辑日志和镜像文件到内存,并合并。(所谓合并,就是将Edits和Fsimage加载到内存中,照着Edits中的操作一步步执行,最终形成新的Fsimage)
  • 生成新的镜像文件fsimage.chkpoint。
  • 通过post方式将新的fsimage.chkpoint文件发送到NameNode节点上。
  • NameNode将fsimage.chkpoint重新命名成fsimage,替换旧的FsImage文件,同时将edits.inprogress替换EditLog文件,通过这个过程EditLog就变小了。

除了这个自带的备份操作,还需要进行人工的备份,把一份fsimage到多个地方进行备份,万一namenode的节点坏了呢。

(2)NameNode的安全模式

NameNode 在启动时会自动进入安全模式。安全模式是NameNode的一种状态,在这个阶段,文件系统不允许有任何修改。安全模式的目的是在系统启动时检查各个DataNode上数据块的有效性,同时根据策略对数据块进行必要的复制或删除。如果块损坏的太多,则namenode会一直处在安全模式,从而导致HDFS不能操作。当数据块最小百分比数满足配置的“最小副本数条件”时,会自动退出安全模式。

所谓的最小副本条件指的是在整个文件系统中有99.9%的块满足最小副本级别(默认值是1,由dfs.namenode.replication.min属性设置)。

namenode启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项编辑操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件(该操作不需要借助secondary namenode)和一个空的编辑日志。在这个过程中,namenode运行着安全模式,意味着namenode的文件系统对于客户端来说是只读的。

(3)Fsimage和Edits解析

Fsimage和Edits解析
注意:每次重启NameNode都产生新的fsimage和edits文件。

【oiv】
  • 1.用于查看Hadoop fsimage
  • 2.语法
    $> hdfs oiv -i inputfile -o outputfile -p process
  • 3.inputfile: 要查看的fsimage文件
    outputfile: 用于保存格式化之后的文件
    process: 使用什么进程解码,XML|Web|…
  • 4.案例实操:
[qinjl@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current

[qinjl@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml

[qinjl@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml
  • 5.部分显示结果如下:
<inode>
	<id>16386</id>
	<type>DIRECTORY</type>
	<name>user</name>
	<mtime>1512722284477</mtime>
	<permission>qinjl:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16389</id>
	<type>FILE</type>
	<name>wc.input</name>
	<replication>3</replication>
	<mtime>1512722322219</mtime>
	<atime>1512722321610</atime>
	<perferredBlockSize>134217728</perferredBlockSize>
	<permission>qinjl:supergroup:rw-r--r--</permission>
	<blocks>
		<block>
			<id>1073741825</id>
			<genstamp>1001</genstamp>
			<numBytes>59</numBytes>
		</block>
	</blocks>
</inode >
  • 6.思考:可以看出,Fsimage中没有记录块所对应DataNode,为什么?

从以上fsimage中加载的namenode内存中的信息中可以很明显的看出,在fsimage中,并没有记录每一个block对应到哪几个datanodes的对应表信息,而只是存储了所有的关于namespace的相关信息。而真正每个block对应到datanodes列表的信息在hadoop中并没有进行持久化存储,而是在所有datanode启动时,每个datanode对本地磁盘进行扫描,将本datanode上保存的block信息汇报给namenode,namenode在接收到每个datanode的块信息汇报后,将接收到的块信息,以及其所在的datanode信息等保存在内存中。(HDFS就是通过这种块信息汇报的方式来完成 block -> datanodes list的对应表构建。Datanode向namenode汇报块信息的过程叫做blockReport,而namenode将block -> datanodes list的对应表信息保存在一个叫BlocksMap的数据结构中。)

blockReport(块状态报告),datanode启动时会报告一次,之后周期性(默认6小时) 的向 namenode 上报所有的块信息。namenode根据datanode汇报结果进行删除多余块以及复制副本不足的块等操作。汇报dn上保存了哪些block,分别属于哪些文件,健康状况如何等

【oev】
  • 1.用于查看Hadoop 的 edit 文件
  • 2.语法
    $> hdfs oev -i inputfile -o outputfile -p process
  • 3.inputfile: 要查看的edit文件
    outputfile: 用于保存格式化之后的文件
    process: 使用什么进程解码,XML|Web|…
  • 4.案例实操:
[qinjl@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml

[qinjl@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/edits.xml
  • 5.部分显示结果如下:
 <?xml version="1.0" encoding="UTF-8"?>
<EDITS>
	<EDITS_VERSION>-63</EDITS_VERSION>
	<RECORD>
		<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
		<DATA>
			<TXID>129</TXID>
		</DATA>
	</RECORD>
	<RECORD>
		<OPCODE>OP_ADD</OPCODE>
		<DATA>
			<TXID>130</TXID>
			<LENGTH>0</LENGTH>
			<INODEID>16407</INODEID>
			<PATH>/hello7.txt</PATH>
			<REPLICATION>2</REPLICATION>
			<MTIME>1512943607866</MTIME>
			<ATIME>1512943607866</ATIME>
			<BLOCKSIZE>134217728</BLOCKSIZE>
			<CLIENT_NAME>DFSClient_NONMAPREDUCE_-1544295051_1</CLIENT_NAME>
			<CLIENT_MACHINE>192.168.1.5</CLIENT_MACHINE>
			<OVERWRITE>true</OVERWRITE>
			<PERMISSION_STATUS>
				<USERNAME>qinjl</USERNAME>
				<GROUPNAME>supergroup</GROUPNAME>
				<MODE>420</MODE>
			</PERMISSION_STATUS>
			<RPC_CLIENTID>908eafd4-9aec-4288-96f1-e8011d181561</RPC_CLIENTID>
			<RPC_CALLID>0</RPC_CALLID>
		</DATA>
	</RECORD>
	<RECORD>
		<OPCODE>OP_ADD_BLOCK</OPCODE>
		<DATA>
			<TXID>133</TXID>
			<PATH>/hello7.txt</PATH>
			<BLOCK>
				<BLOCK_ID>1073741839</BLOCK_ID>
				<NUM_BYTES>0</NUM_BYTES>
				<GENSTAMP>1016</GENSTAMP>
			</BLOCK>
			<RPC_CLIENTID></RPC_CLIENTID>
			<RPC_CALLID>-2</RPC_CALLID>
		</DATA>
	</RECORD>
</EDITS >
  • 6.思考:NameNode如何确定下次开机启动的时候合并哪些Edits?
    只会合并比fsimage编号大的edits文件.

(4)CheckPoint时间设置

  • 通常情况下,SecondaryNameNode每隔一小时执行一次。
    [hdfs-default.xml]
<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600s</value>
</property>
  • 一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次
<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
<description>操作动作次数</description>
</property>

<property>
  <name>dfs.namenode.checkpoint.check.period</name>
  <value>60s</value>
<description> 1分钟检查一次操作次数</description>
</property>

7、DataNode详解

(1)DataNode工作机制

DataNode工作机制

  • 一个数据块在 datanode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
  • DataNode 启动后向 namenode 注册, 通过后,周期性(6小时) 的向 namenode 上报所有的块信息(块状态报告Blockreport)。
  • 心跳是每 3 秒一次,心跳返回结果带有 namenode 给该 datanode 的命令如复制块数据到另一台机器,或删除某个数据块。 如果超过 10 分钟没有收到某个 datanode 的心跳,则认为该节点不可用。
  • 集群运行中可以安全加入和退出一些机器。

(2)心跳机制

HDFS心跳机制
工作原理:

  • master(NameNode)启动的时候,会开一个ipc server在那里。
  • slave(DataNode)启动,连接master,每隔3秒钟向master发送一个“心跳”,携带状态信息;
  • master通过这个心跳的返回值,向slave节点传达指令

作用:

  • Namenode全权管理数据块的复制,它周期性地从集群中的每个Datanode接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着该Datanode节点工作正常。块状态报告包含了一个该 Datanode上所有数据块的列表
  • DataNode启动后向NameNode注册,通过后,周期性(1小时)的向 NameNode上报所有的块的列表;每3秒向NameNode发一次心跳,返回NameNode给该DataNode的命令;如复制块数据到另一台机器,或删除某个数据块。如果NameNode超过10分钟没有收到某个DataNode 的心跳,则认为该节点不可用。
  • hadoop集群刚开始启动时,会进入安全模式(99.9%),就用到了心跳机制
  • 集群节点之间必须做时间同步,namenode是集群的老大,负责集群上任务的分工,如果要进行分工,则必须知道各个从节点的存活状况。

namenode什么时候会判定datanode死了?

答:datanode每隔3秒向namenode发送一次心跳报告,当namenode连续10次没有收到datanode的心跳报告则认为这个datanode可能死了,并没有判定死了(可能网络延迟),这个时候namenode会主动向datanode发送一次检查,发送一次检查的时间是5min(300000毫秒),如果一次检查没有返回信息,这时候namenode会再进行一次检查,如果再获取不到datanode的返回信息,这个时候才会判定当前的datanode死亡了。
即:namenode最终判断datanode死亡需要10min+30s=630s。namenode在连续630s中没有得到datanode的信息才会认为当前的datanode宕机。

生产环境中,如果觉得网络可能会延迟,可以延长上述两个参数。

<property>
    <name>dfs.heartbeat.interval</name>
	 <value>3</value>    
    <description>Determines datanode heartbeat interval in seconds. </description>
</property>   
<property>                                           
  <name>dfs.namenode.heartbeat.recheck-interval</name>
	 <value>300000</value>    
  <description>This time decides the interval to check for expired datanodes.With this value and dfs.heartbeat.interval, the interval of deciding the datanode id stale ot not is also calculated. The unit of this configuration is millisecond.                                                 </description>
</property>

(3)数据完整性

DataNode节点上的数据损坏了,却没有发现,是很危险的,那么如何解决呢?
如下是DataNode节点保证数据完整性的方法。

  • (1)当DataNode读取Block的时候,它会计算并校验CheckSum(校验和)。
  • (2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
  • (3)Client读取其他DataNode上的Block。
  • (4)常见的校验算法crc(32),md5(128),sha1(160)
  • (5)DataNode在其文件创建后周期验证CheckSum。
    在这里插入图片描述

检测数据是否损坏的常见措施是,在数据第一次引入系统时计算校验和(checksum)并存储,在数据进行传输后再次计算校验和进行对比,如果计算所得的新校验和和原来的校验和不匹配,就认为数据已损坏。但该技术并不能修复数据——它只能检测出数据错误。(这正是不使用低端硬件的原因。具体说来,一定要使用ECC内存。)注意,校验和也是可能损坏的,不只是数据,但由于校验和比数据小得多,所以损坏的可能性非常小。

HDFS以透明的方式检验所有写入它的数据,并在默认设置下,会在读取数据时验证校验和。正对数据的每一个校验块,都会创建一个单独的校验和,默认校验块大小是512字节(即上文提到的chunk单位,这个值由io.bytes.per.checksum指定),对应的校验和是4字节。

一般来说,HDFS会在三种情况下检验校验和:

(一)DataNode接收数据后存储数据前
DataNode接收数据一般有两种情况:1.从客户端上传数据 2.DataNode从其他DataNode上接收数据。
当客户端上传数据时,正在写数据的客户端将数据及其校验和发送到由一系列datanode组成的Pipeline管线。Pipeline管线中最后一个datanode负责验证校验和。

DataNode数据存储步骤:(包括从DataNode和客户端两种传输方式)
1.在传输数据的最开始阶段,Hadoop会简单地检查数据块的完整性信息;
2.依次向各个DataNode传输数据,包括数据头信息、块信息、备份个数、校验和等;
3.Hadoop不会在数据每流动到一个DataNode都检查校验和,只会在数据流达到最后一个节点时才检查校验和
如果在验证过程中发现有不一致的块,就会抛出CheckSumException异常信息

(二)客户端读取DataNode上的数据时
Hadoop会在客户端读取DataNode上的数据时,使用DFSClient中的read函数先将数据读入到客户端的数据缓冲区,然后由客户端检查校验和。将他们与datanode中存储的校验和进行比较
每个datanode均持久保存有一个用于验证的校验和日志,所以它知道每个数据块的最后一次验证时间
客户端成功验证一个数据块后,会告诉这个datanode,datanode由此更新日志

(三)DataNode后台守护进程的定期检查
DataNode会在后台运行DataBlockScanner,这个程序定期验证存储在这个datanode上的所有数据块(3周)
该项措施是解决物理存储媒体上位衰减,位损坏的有力措施。

Hadoop处理损坏数据的机制:

  • 客户端在读取数据检查校验和时,如果发现本次计算的校验和跟DataNode上存储的校验和不一致,则认为该block块已损坏
  • 客户端在抛出ChecksumException之前上报该block信息给namenode进行标记(“已损坏”),这样namenode就不会把客户端指向这个block,也不会复制这个block到其他的datanode。
  • client重新读取另外的datanode上的block
  • 在心跳返回时NameNode将块的复制任务交给DataNode,从完好的block副本进行复制以达到默认的备份数3
  • NameNode删除掉坏的block。
  • DataNode在一个block块被创建之日起三周后开始进行校验

如果出于一些原因在操作的时候不想让hdfs检查校验码
在用 hdfs dfs get 命令读取文件时,可以用 -ignoreCrc 忽略验证。
或者直接使用-copyToLocal
如果是通过FileSystem API 读取时,可以通过fs.setVerifyChecksum(false),忽略验证。

(4)判断DataNode掉线时限参数设置

datanode 进程死亡或者网络故障造成 datanode 无法与 namenode 通信, namenode 不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。 HDFS 默认的超时时长为 10 分钟+30 秒(详情见第7点DataNode详解中的心跳机制)。如果定义超时时间为 timeout,则超时时长的计算公式为:

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

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

可以在hdfs-site.xml里修改相关配置(hdfs-site.xml 在hadoop安装目录下的etc下的hadoop里)

<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

需要注意的是 hdfs-site.xml 配置文件中的 heartbeat.recheck.interval 的单位为毫秒,dfs.heartbeat.interval 的单位为秒。

(5)datanode块汇报机制

汇报dn上保存了哪些block,分别属于哪些文件,健康状况如何等

datanode块汇报分为两种,IBR(增量块汇报incremental block reports)、FBR(全量块汇报 full block reports )。DataNode的BPServiceActor线程在datanode启动后会一直执行,持续循环发送heartbeat、IBR、FBR。然后根据增量块汇报会更新各种记录时间的变量用来辅助调用IBR。比如强制触发IBR等 。

IBR: 注意dfs.blockreport.incremental.intervalMsec 默认值是0 。 也就是说只要datanode有如下三种块变动,即可就会向namenode汇报:1.接受完毕(写完)的块。2.刚刚删除完成的块。3.正在接收(写入)的块。这样的好处是元数据维护的及时更新,坏处是过多的RPC请求会增加namenode的负载(因为更新元数据的锁机制)。如果公司集群单namenode,负载很高的话,可以适当将这个值调整一些比如200ms,实现datanode的IBR延时汇报,这样datanode可以在间隔时内积攒的所有block一次提交给namenode,进而降低namenode的负载。

FBR:上面说了IBR是针对增量块的变动汇报。datanode的上block的元数据信息,如block位置,block的状态等信息都存放在内存中。每隔6个小时,datanode会进行一次Directory Scanners(具体参dfs.datanode.directoryscan.interval =21600),通过Directory Scannners(扫描自己节点块信息列表)检查内存中block信息和磁盘上实际存储的block一致性情况。当Directory Scanners发现block文件、meta文件丢失时,或者多余时(即和磁盘存储的结果不一致的那些block),会将block标记为corrupted/invalidates等,datanode然后在下一次汇报中(3s心跳机制),将这个块汇报给namenode。注意Directory Scanners只检查finalized状态的block(增量block不管)。因为FBR给namenode的压力太大,尤其对于几亿blocks的大集群来说,所以每个datanode的全量块汇报是在6个小时内逐步完成的(多批次)。这样的结果就是节点非增量块的丢失一般极限的话要6个小时后namenode才会感知,并且通知到用户。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值