hadoop之hdfs02

一、hdfs概述

1.概念

HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改,如果发现文件错误,可以删除重新上传。

2.优缺点

  1. 优点
    (1) 高容错性
    a) 数据自动保存多个副本。它通过增加副本的形式,提高容错性;
    b) 某一个副本丢失以后,其它副本有备份,能够自动恢复。
    (2) 适合大数据处理
    a) 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据。
    b) 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
    (3) 部署成本低,可构建在廉价机器上,通过多副本机制,提高可靠性。

  2. 缺点
    (1) 不适合低延时数据访问,比如像mysql那样毫秒级的读写数据,是做不到的。
    (2) 无法高效的对大量小文件进行存储。
    a) 存储大量小文件的话,它会占用NameNode更多的内存来存储文件的元数据。这样是不可取的,因为NameNode的内存总是有限的。在hdfs里面,每个block的元数据会占用150字节的内存空间。例如同样存储10M的内容,采取副本数为3的备份机制,这10M放在一个文件中,所用到的元数据占用的内存为1503=450字节,如果把这10M放到10个文件中,则占用15010*3=4500字节,很明显,存储相同的内容,第二种方式浪费的内存更多。
    b) 小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
    i. 寻址时间,目前技术水平在10ms左右
    ii. 传输 1
    寻址时间/传输时间=1%,传输时间1000ms=1s,磁盘传输速度100M/S,计算机是2
    的n次方,所以hadoop2.x默认块的大小为128M。
    (3) 不支持并发写入(即多个用户同时写一个文件)、文件随机修改(文件任意位置写)。
    a) 一个文件只能有一个用户写,不允许多个线程同时写;
    b) 仅支持数据append(追加),不支持文件的随机修改。

3.hdfs组成架构

在这里插入图片描述

(1) Client:就是客户端。
a) 文件切分。文件上传HDFS的时候,并不是把一个大文件原封不动的上传上去,而而是由Client先将文件切分成一个一个的block,然后按照block进行存储
b) 与NameNode交互,获取文件的位置信息,客户端要想传输数据,必须先于namenode通信,获取相应的datanode的地址。
c) 与DataNode交互,读取或者写入数据,datanode是实际负责存储文件的。
d) Client提供一些命令来管理HDFS,比如启动或者关闭HDFS;
e) Client可以通过一些命令来访问HDFS。
(2) NameNode:就是Master,它是一个主管、管理者,类似于会计,管账的。
a) 管理HDFS的名称空间;namespace
b) 管理数据块(Block)映射信息;
c) 配置副本策略(默认)3
d) 处理客户端读写请求。
(3) DataNode:就是Slave,干活的,类似于出纳,管钱。NameNode下达命令,DataNode执行实际的操作,datanode是进程,它在接收到用户传递过来的数据后,将数据存储到本地的文件系统。
a) 存储实际的数据块;
b) 执行数据块的读/写操作。
(4) SecondaryNameNode:并非NameNode的热备。所谓的热备指的是,当namenode挂了之后,secondarynamenode马上就成承担namenode的任务。而实际上,当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
a) 辅助NameNode,分担其工作量;
b) 定期合并fsimage和Edits,并推送给NameNode;
c) 在紧急情况下,可辅助恢复NameNode。

二、 HDFS的Shell客户端操作

常用命令

  1. 启动Hadoop集群
[root@hadoop003 hadoop-2.7.2]$ sbin/start-dfs.sh
[root@hadoop102 hadoop-2.7.2]$ sbin/start-yarn.sh
  1. -ls: 显示目录信息
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -ls /
  1. -mkdir:在hdfs上创建目录
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -mkdir -p /aaa/bbb
  1. -appendToFile :追加一个文件到已经存在的文件末尾
[root@hadoop003 hadoop-2.7.2]$ touch world.txt
[root@hadoop003 hadoop-2.7.2]$ vim world.txt
输入
world bigdata
[root@hadoop102 hadoop-2.7.2]$ hadoop fs -appendToFile world.txt /aaa/bbb/hello.txt
  1. -cat:显示文件内容
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -cat /aaa/bbb/hello.txt
  1. -tail:显示一个文件的末尾
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -tail /aaa/bbb/hello.txt
  1. -chgrp 、-chmod、-chown:linux文件系统中的用法一样,修改文件所属权限
[root@hadoop003 hadoop-2.7.2]$ hadoop fs  -chmod  666  /aaa/bbb/hello.txt
[root@hadoop003 hadoop-2.7.2]$ hadoop fs  -chown  root:root   /aaa/bbb/hello.txt
  1. -cp :从hdfs的一个路径拷贝到hdfs的另一个路径
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -cp /aaa/bbb/hello.txt /bigdata.txt
  1. -mv:在hdfs目录中移动文件
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -mv /bigdata.txt /aaa/bbb/
  1. -get:等同于copyToLocal,就是从hdfs下载文件到本地
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -get /aaa/bbb/hello.txt ./
  1. -put:等同于copyFromLocal从本地上传文件到hdfs
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -put ./allfile.txt /aaa/bbb/
  1. -rm:删除文件或文件夹
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -rm -r /user/root/test.txt
  1. -du统计文件夹的大小信息
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -du -s -h /user/root/test
2.7 K  /user/root/test
[root@hadoop102 hadoop-2.7.2]$ hadoop fs -du  -h /user/root/test
1.3 K  /user/root/test/README.txt
15     /user/root/test.txt
1.4 K  /user/root/test/allfile.txt
  1. -setrep:设置hdfs中文件的副本数量
[root@hadoop003 hadoop-2.7.2]$ hadoop fs -setrep 10 /aaa/bbb/hello.txt

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

三、 HDFS的Java客户端操作

1、 HDFS客户端环境准备

  1. 根据自己电脑的操作系统拷贝对应的编译后的hadoop jar包到非中文路径,如图所示:
    在这里插入图片描述

  2. 配置HADOOP_HOME环境变量,如图所示:
    在这里插入图片描述

  3. 配置Path环境变量,如图所示:
    在这里插入图片描述

  4. 创建一个Maven工程myhdfs

  5. 导入相应的依赖坐标+日志添加

<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.8.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-common</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-client</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-hdfs</artifactId>
			<version>2.7.2</version>
		</dependency>
</dependencies>

控制台打印日志,在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入:

log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

2、 创建HdfsClient类,执行相关api操作

public class HdfsClient {
    @Test//创建目录
    public void test() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        boolean mkdirs = fs.mkdirs(new Path("/033002"));
        System.out.println("是否创建成功"+mkdirs);
    }
    @Test//文件上传
    public void testUpload() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        fs.copyFromLocalFile(new Path("E:\\java\\a.txt"),new Path("/033002"));
        System.out.println("上传成功");
    }
    @Test//文件下载
    public void testDownload() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        fs.copyToLocalFile(new Path("/033002/a.txt"),new Path("E:/java/q.txt"));
        System.out.println("下载成功");
    }
    @Test//文件删除
    public void testDelete() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        boolean delete = fs.delete(new Path("/033002/a.txt"), true);

        System.out.println("是否删除"+delete);
    }
    @Test//文件名更改
    public void testRename() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        boolean idea = fs.rename(new Path("/033002"), new Path("/idea"));
        System.out.println("是否改名成功"+idea);
    }

    @Test//文件和文件夹判断
    public void testFileOrDirectory() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.使用hdfs的客户端对象去操作hdfs
        boolean directory = fs.isDirectory(new Path("/idea"));
        System.out.println("是否为文件夹"+directory);
        boolean file = fs.isFile(new Path("/aaa/test.txt"));
        System.out.println("是否为文件"+file);
        //遍历判断整个文件夹内的文件
        FileStatus[] fileStatuses = fs.listStatus(new Path("/bbb"));
        for (FileStatus f:fileStatuses){
            if(f.isDirectory()){
                System.out.println(f.getPath().getName()+"是文件夹");
            }else{
                System.out.println(f.getPath().getName()+"是文件,"+f.getLen()+","+f.getPermission());
            }
        }

    }

    @Test//io流上传
    public void testIoUpload() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.创建输入流
        FileInputStream is = new FileInputStream("E:/java/c.txt");
        //4.创建输出流
        FSDataOutputStream os = fs.create(new Path("/idea/c.txt"));
        //5.流的对接
        IOUtils.copyBytes(is,os,conf);
        //6.资源关闭
        IOUtils.closeStream(is);
        IOUtils.closeStream(os);
        fs.close();
    }
    @Test//io流下载
    public void testIoDownload() throws Exception {
        //1 创建一个配置对象
        Configuration conf = new Configuration();
        //2 根据配置对象,创建hdfs的客户端对象
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop003:9000"), conf, "root");
        //3.创建输入流
        FSDataInputStream is = fs.open(new Path("/idea/c.txt"));
        //4.创建输出流
        FileOutputStream os = new FileOutputStream("E:/java/io.txt");
        //5.流的对接
        IOUtils.copyBytes(is,os,conf);
        //6.资源关闭
        IOUtils.closeStream(is);
        IOUtils.closeStream(os);
        fs.close();
    }
}

(2) 更改文件的副本数量
将hdfs-site.xml拷贝到项目的根目录下

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
	<property>
		<name>dfs.replication</name>
        <value>1</value>
	</property>
</configuration>

(3) 参数优先级
参数优先级排序: (1)客户端代码中设置的值 >(2)classpath下的用户自定义配置文件 >(3)然后是服务器的默认配置

四、 HDFS的数据流

1、 HDFS写数据流程

在这里插入图片描述
(1) 客户端向hdfs上传文件,首先向NameNode请求上传文件,NameNode会做一些验证,比如检查目标文件是否已存在,父目录是否存在。
(2) NameNode经过验证后,向客户端返回是否可以上传。
(3) 如果客户端收到可以上传的回复,则会向namenode请求第一个 block上传到哪几个datanode服务器上。
(4) NameNode返回客户端可用的3个datanode的节点地址,选择原则根据哪台节点机器距离近,负载小,分别为datanode1、datanode2、datanode3,表示往这三个节点上存数据。
(5) 客户端通过FSDataOutputStream模块请求datanode1上传数据,datanode1收到请求会继续调用datanode2,然后datanode2调用datanode3,将这个通信管道建立完成。
(6) datanode1、datanode2、datanode3逐级应答客户端。
(7) 客户端开始往datanode1上传第一个block,以packet为单位,发送一个一个的packet包,datanode1收到一个packet在内存中留一份,再存储到本地磁盘一份,还会将内存中该packet复制一份传给datanode2,datanode2传给datanode3;
(8) 当一个block传输完成之后,会清空每台节点上内存数据,响应客户端上传成功,客户端会告诉namenode上传完毕,客户端再次请求NameNode上传第二个block的服务器。(重复执行3-7步)。

网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。
在这里插入图片描述
在这里插入图片描述

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

Hadoop2.7.2副本节点选择
在这里插入图片描述

2、 HDFS读数据流程

在这里插入图片描述
(1) 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2) 挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3) DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)。
(4) 客户端以packet为单位接收,先在本地缓存,然后写入目标文件。
(5) 客户端将所有的块下载下来之后,在本地将所有的块拼接成一个文件。

五、 NameNode和SecondaryNameNode工作机制

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

首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。

1、 NN和2NN工作机制

在这里插入图片描述

(1) 第一阶段:NameNode启动
a) 第一次启动NameNode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志(位于磁盘上,存储的是生成元数据的步骤,执行后会生成元数据)和镜像文件(位于磁盘上,存储的是文件的元数据)到内存。
b) 客户端向namenode发出对元数据进行增删改的请求。Namenode在接收这些请求的时候,并不是直接写到内存里面,因为写到内存的话,断电会丢失,因此将这些请求分为一个个小步骤写入到位于磁盘上的编辑日志,这样即使断电,也能从磁盘中恢复出这些数据。
c) NameNode将存储完成的编辑日志执行一遍形成元数据写入到内存,如果edits.inprogress中的编辑日志满了,则会按照编号将其重命名,并创建新的edits.inprogress文件接收新请求,即滚动编辑日志。
d) NameNode在内存中对数据进行增删改查。
(2) 第二阶段:Secondary NameNode工作
a) Secondary NameNode询问NameNode是否需要checkpoint。直接带回NameNode是否检查结果。
b) Secondary NameNode请求执行checkpoint。
c) NameNode滚动正在写的edits日志。
d) 将滚动前的编辑日志(最新的,未被使用的)和镜像文件拷贝到Secondary NameNode。
e) Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
f) 生成新的镜像文件fsimage.chkpoint。
g) 将fsimage.chkpoint重新命名成fsimage。
h) 拷贝fsimage到NameNode。

2、 NN和2NN工作机制详解:

fsimage:namenode内存中元数据序列化后形成的文件。
edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。
namenode启动时,先滚动edits并生成一个空的edits.inprogress,然后加载edits(归档后的)和fsimage(最新的)到内存中,此时namenode内存就持有最新的元数据信息。client开始对namenode发送元数据的增删改查的请求,这些请求的操作首先会被记录在edits.inprogress中(查询元数据的操作不会被记录在edits中,因为查询操作不会更改元数据信息),如果此时namenode挂掉,重启后会从edits中读取元数据的信息。然后,namenode会在内存中执行元数据的增删改查的操作。
由于edits中记录的操作会越来越多,edits文件会越来越大,导致namenode在启动加载edits时会很慢,所以需要对edits和fsimage进行合并(所谓合并,就是将edits和fsimage加载到内存中,照着edits中的操作一步步执行,最终形成新的fsimage)。Secondarynamenode:帮助namenode进行edits和fsimage的合并工作。
secondarynamenode首先会询问namenode是否需要checkpoint(触发checkpoint需要满足两个条件中的任意一个,定时时间到和edits中数据写满了)。直接带回namenode是否checkpoint结果。secondarynamenode执行checkpoint操作,首先会让namenode滚动edits并生成一个空的edits.inprogress,滚动edits的目的是给edits打个标记,以后所有新的操作都写入edits.inprogress,其他未合并的edits和fsimage会拷贝到secondarynamenode的本地,然后将拷贝的edits和fsimage加载到内存中进行合并,生成fsimage.chkpoint,然后将fsimage.chkpoint拷贝给namenode,重命名为fsimage后替换掉原来的fsimage。namenode在启动时就只需要加载之前未合并的edits和fsimage即可,因为合并过的edits中的元数据信息已经被记录在fsimage中。

3、 Fsimage和Edits解析

思考:可以看出,Fsimage中没有记录块所对应DataNode,为什么?
在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。

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

根据seen_txid中保存的数字![在这里插入图片描述](https://img-blog.csdnimg.cn/20201117140353921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MzMxMjU1,size_16,color_FFFFFF,t_70#pic_center)

4、 checkpoint时间设置

(1) 通常情况下,SecondaryNameNode每隔一小时执行一次。如果修改,在hdfs-site中修改。
默认值在[hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
</property>

(2) 一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
<description>操作动作次数</description>
</property>

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

5、 集群安全模式

1) 概述

NameNode启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作。同时,NameNode开始监听DataNode请求,因为hdfs的文件是以块列表的形式存储在DataNode中的,datanode要向namenode汇报它们所维护的块信息,这样namenode才能知道这些块信息,才能够对外正常提供服务。此刻,NameNode运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,才可对外正常提供服务。
也就是说namenode在刚启动的时候,没有收集到足够多的块信息,还不能对外提供服务,需要在安全模式下做好准备,那么什么时候才认为是收集了足够多的块信息了呢?
如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。

2) 基本语法

集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。
(1) bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)
(2) bin/hdfs dfsadmin -safemode enter (功能描述:进入安全模式状态)
(3) bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
(4) bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态,监控安全模式)

3) 案例

模拟等待安全模式
(1) 先进入安全模式

[root@hadoop003 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode enter

(2) 执行下面的脚本
编辑一个脚本

#!/bin/bash
bin/hdfs dfsadmin -safemode wait(安全模式关闭)
bin/hdfs dfs -put ~/hello.txt /root/hello.txt

(3) 再打开一个窗口,执行

[root@hadoop003 hadoop-2.7.2]$ bin/hdfs dfsadmin -safemode leave

六、 DataNode工作机制

在这里插入图片描述
(1) 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2) DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
(3) 心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。

数据完整性

思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?
如下是DataNode节点保证数据完整性的方法。
1)当DataNode读取Block的时候,它会计算CheckSum。
2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
3)Client读取其他DataNode上的Block。
4)DataNode在其文件创建后周期验证CheckSum
在这里插入图片描述

超时时长参数设置

在这里插入图片描述
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。

<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name>dfs.heartbeat.interval</name>
    <value>3</value>
</property>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值