欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hadoop-HDFS(详解)

程序员文章站 2024-03-22 13:52:34
...

大家好,我是AC.
接着写Hadoop,不是讲完了?当然不是,前面是对Hadoop体系,大致介绍了下,后几篇文章会细讲每个重要的组成部分,今天是介绍HDFS:

一、HDFS概述

1、HDFS产生背景

随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。

2、HDFS概念

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

3、HDFS优缺点

知道优缺点,方便进行技术选型。

1)优点

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

2)缺点

(1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
(2)无法高效地对大量小文件进行存储。
a)存储大量小文件的话,它会占用NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,因为NameNode的内存总是有限的。1 kb 1kb 1kb 150字节 100MB 150字节
b)小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
i.寻址时间,目前技术水平在10ms左右
ii.传输
寻址时间/传输时间=1%,传输时间1000ms=1s,磁盘传输速度100M/S,计算机是2
的n次方,所以hadoop2.x默认块的大小为128M。
(3)不支持并发写入、文件随机修改。
a)一个文件只能有一个写,不允许多个线程同时写;
b)仅支持数据append(追加),不支持文件的随机修改

4、HDFS组成架构

HDFS组成架构如图所示:
Hadoop-HDFS(详解)
架构主要由四个部分组成,分别为HDFS ClientNameNodeDataNodeSecondary NameNode。下面我们分别介绍这四个组成部分。
(1)Client:就是客户端。
a)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行存储;
b)与NameNode交互,获取文件的位置信息;
c)与DataNode交互,读取或者写入数据;

d)Client提供一些命令来管理HDFS,比如启动或者关闭HDFS;
e)Client可以通过一些命令来访问HDFS。
(2)NameNode:就是Master,它是一个主管、管理者。
a)管理HDFS的名称空间;namespace
b)管理数据块(Block)映射信息;
c)配置副本策略(默认);3
d)处理客户端读写请求。
(3)DataNode:就是Slave(奴隶)。NameNode下达命令,DataNode执行实际的操作。
a)存储实际的数据块;
b)执行数据块的读/写操作。
(4)SecondaryNameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
a)辅助NameNode,分担其工作量;
b)定期合并fsimageEdits,并推送给NameNode
c)在紧急情况下,可辅助恢复NameNode

5、HDFS文件块大小

HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M。

二、HDFS的Shell客户端操作

1、基本语法

bin/hadoop fs 具体命令

2、命令大全

[aaa@qq.com hadoop-2.7.2]# bin/hadoop fs
[-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] <localsrc> ... <dst>]
        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-count [-q] <path> ...]
        [-cp [-f] [-p] <src> ... <dst>]
        [-createSnapshot <snapshotDir> [<snapshotName>]]
        [-deleteSnapshot <snapshotDir> <snapshotName>]
        [-df [-h] [<path> ...]]
        [-du [-s] [-h] <path> ...]
        [-expunge]
        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-getfacl [-R] <path>]
        [-getmerge [-nl] <src> <localdst>]
        [-help [cmd ...]]
        [-ls [-d] [-h] [-R] [<path> ...]]
        [-mkdir [-p] <path> ...]
        [-moveFromLocal <localsrc> ... <dst>]
        [-moveToLocal <src> <localdst>]
        [-mv <src> ... <dst>]
        [-put [-f] [-p] <localsrc> ... <dst>]
        [-renameSnapshot <snapshotDir> <oldName> <newName>]
        [-rm [-f] [-r|-R] [-skipTrash] <src> ...]
        [-rmdir [--ignore-fail-on-non-empty] <dir> ...]
        [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
        [-setrep [-R] [-w] <rep> <path> ...]
        [-stat [format] <path> ...]
        [-tail [-f] <file>]
        [-test -[defsz] <path>]
        [-text [-ignoreCrc] <src> ...]
        [-touchz <path> ...]
        [-usage [cmd ...]]

3、常用命令实操

1)启动Hadoop集群(方便后续的测试)

[aaa@qq.com hadoop-2.7.2]# sbin/start-dfs.sh
[aaa@qq.com hadoop-2.7.2]# sbin/start-yarn.sh

2)-help:输出这个命令参数

[aaa@qq.com hadoop-2.7.2]# hadoop fs -help rm

3)-ls: 显示目录信息

[aaa@qq.com hadoop-2.7.2]# hadoop fs -ls /

4)-mkdir:在hdfs上创建目录

[aaa@qq.com hadoop-2.7.2]# hadoop fs -mkdir -p /sanguo/shuguo

5)-moveFromLocal从本地剪切粘贴到hdfs

[aaa@qq.com hadoop-2.7.2]# touch kongming.txt
[aaa@qq.com hadoop-2.7.2]# hadoop fs  -moveFromLocal  ./kongming.txt  /sanguo/shuguo

6)-appendToFile :追加一个文件到已经存在的文件末尾

[aaa@qq.com hadoop-2.7.2]# touch liubei.txt
[aaa@qq.com hadoop-2.7.2]# vim liubei.txt
输入
san gu mao lu
[aaa@qq.com hadoop-2.7.2]# hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt

7)-cat:显示文件内容

[aaa@qq.com hadoop-2.7.2]# hadoop fs -cat /sanguo/shuguo/kongming.txt

8)-tail:显示一个文件的末尾

[aaa@qq.com hadoop-2.7.2]# hadoop fs -tail /sanguo/shuguo/kongming.txt

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

[aaa@qq.com hadoop-2.7.2]# hadoop fs  -chmod  666  /sanguo/shuguo/kongming.txt
[aaa@qq.com hadoop-2.7.2]# hadoop fs  -chown  root:root   /sanguo/shuguo/kongming.txt

10)-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去

[aaa@qq.com hadoop-2.7.2]# hadoop fs -copyFromLocal README.txt /

11)-copyToLocal:从hdfs拷贝到本地

[aaa@qq.com hadoop-2.7.2]# hadoop fs -copyToLocal /sanguo/shuguo/kongming.txt ./

12)-cp :从hdfs的一个路径拷贝到hdfs的另一个路径

[aaa@qq.com hadoop-2.7.2]# hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt

13)-mv:在hdfs目录中移动文件

[aaa@qq.com hadoop-2.7.2]# hadoop fs -mv /zhuge.txt /sanguo/shuguo/

14)-get:等同于copyToLocal,就是从hdfs下载文件到本地

[aaa@qq.com hadoop-2.7.2]# hadoop fs -get /sanguo/shuguo/kongming.txt ./

15)-getmerge :合并下载多个文件,比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,…

[aaa@qq.com hadoop-2.7.2]# hadoop fs -getmerge /sanguo/shuguo/* ./zaiyiqi.txt

16)-put:等同于copyFromLocal

[aaa@qq.com hadoop-2.7.2]# hadoop fs -put ./zaiyiqi.txt /sanguo/shuguo/

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

[aaa@qq.com hadoop-2.7.2]# hadoop fs -rm /user/root/test/jinlian2.txt

18)-rmdir:删除空目录(了解)

[aaa@qq.com hadoop-2.7.2]# hadoop fs -mkdir /test
[aaa@qq.com hadoop-2.7.2]# hadoop fs -rmdir /test

19)-du统计文件夹的大小信息

[aaa@qq.com hadoop-2.7.2]# hadoop fs -du -s -h /user/root/test
2.7 K  /user/root/test
[aaa@qq.com hadoop-2.7.2]# hadoop fs -du  -h /user/root/test
1.3 K  /user/root/test/README.txt
15     /user/root/test/jinlian.txt
1.4 K  /user/root/test/zaiyiqi.txt

20)-setrep:设置hdfs中文件的副本数量

[aaa@qq.com hadoop-2.7.2]# hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt

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

三、HDFS的Java客户端操作

1、HDFS客户端环境准备

1)根据自己电脑的操作系统拷贝对应的编译后的hadoop jar包到非中文路径(例如:D:\Develop\hadoop-2.7.2),如图所示:
Hadoop-HDFS(详解)
2)配置HADOOP_HOME环境变量,如图所示:
Hadoop-HDFS(详解)
3)配置Path环境变量,如图所示:
Hadoop-HDFS(详解)

4)创建一个Maven工程HdfsClientDemo
工程就不说了
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>

注意:如果eclipse/idea打印不出日志,在控制台上只显示:

1.log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell)
2.log4j:WARN Please initialize the log4j system properly
3.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info

需要在项目的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

6)创建包名:com.hadoop.hdfs
包名也太简单了,就不说了
7)创建HdfsClient类

@Test
public void testName() throws Exception {
	//1 创建一个配置对象
	Configuration conf = new Configuration();
	//2 获取hdfs的客户端
	FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
	//3 通过客户端操作hdfs
	boolean mkdirs = fs.mkdirs(new Path("/user/bbb"));
	System.out.println("是否创建成功:"+mkdirs);
	//4 关闭资源
	fs.close();
}

2、HDFS的API操作

1)HDFS文件上传
(1)编写源代码

@Test
public void upload() throws Exception {
	//1 创建一个配置对象
	Configuration conf = new Configuration();
	//参数设置的优先级 代码>项目>服务器默认
	conf.set("dfs.replication", "4");
	//2 获取hdfs的客户端
	FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
	//3 通过客户端操作hdfs
	fs.copyFromLocalFile(new Path("D:/test/test.jpg"), new Path("/user/test4.jpg"));
	System.out.println("上传成功:");
	//4 关闭资源
	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)然后是服务器的默认配置
2)HDFS文件下载

@Test
	public void download() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
		//参数1:是否删除源文件
		//参数2:源文件路径
		//参数3:目标文件路径
		//参数4:是否开启文件校验
		fs.copyToLocalFile(false, new Path("/user/test4.jpg"), new Path("D:/test/test1225.jpg"), true);
		System.out.println("下载成功:");
		//4 关闭资源
		fs.close();		
	}

3)HDFS文件夹删除

@Test
	public void delete() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
		//参数1:要删除的路径
		//参数2:是否递归删除,如果要删除目录,该参数需要指定为true
		boolean delete = fs.delete(new Path("/user/aaa"), true);
		System.out.println("是否删除成功:"+delete);
		//4 关闭资源
		fs.close();		
	}

4)HDFS文件名更改

@Test
public void rename() throws Exception {
	//1 创建一个配置对象
	Configuration conf = new Configuration();
	//2 获取hdfs的客户端
	FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
	//3 通过客户端操作hdfs
	boolean rename = fs.rename(new Path("/user/bbb"), new Path("/user/ccc"));
	System.out.println("是否重命名成功:"+rename);
	//4 关闭资源
	fs.close();		
}

5)HDFS文件和文件夹判断

	@Test
	public void isFile() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
//		boolean directory = fs.isDirectory(new Path("/user/ccc"));
//		System.out.println("是否为目录:"+directory);
		FileStatus[] listStatus = fs.listStatus(new Path("/user"));
		for (FileStatus fileStatus : listStatus) {
			if(fileStatus.isDirectory()){
				System.out.println(fileStatus.getPath().getName()+"是目录");
			}else{
				System.out.println(fileStatus.getPath().getName()+"不是目录");
			}
		}
		//4 关闭资源
		fs.close();			
	}

6)通过IO流操作HDFS

  • HDFS文件上传
@SuppressWarnings("resource")
@Test
public void ioUpload() throws Exception {
	//1 创建一个配置对象
	Configuration conf = new Configuration();
	//2 获取hdfs的客户端
	FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
	//3 通过客户端操作hdfs
	
	//创建一个输入流,把本地磁盘的文件读取到内存
	FileInputStream fis = new FileInputStream(new File("D:/test/test.jpg"));
	//创建输出流,把读取进内存的数据写出到hdfs
	FSDataOutputStream fsdos = fs.create(new Path("/user/testio.jpg"));
	//边读边写
	IOUtils.copyBytes(fis, fsdos, conf);
	//4 关闭资源
	IOUtils.closeStream(fis);
	IOUtils.closeStream(fsdos);
	fs.close();			
}
  • HDFS文件下载到本地
@Test
	public void ioDownload() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
		
		//创建一个输入流,把hdfs的文件读取到内存
		FSDataInputStream open = fs.open(new Path("/user/testio.jpg"));
		//创建输出流,把读取进内存的数据写出到本地磁盘
		FileOutputStream fos = new FileOutputStream(new File("D:/test/iotest.jpg"));
		//边读边写
		IOUtils.copyBytes(open, fos, conf);
		//4 关闭资源
		IOUtils.closeStream(open);
		IOUtils.closeStream(fos);
		fs.close();			
	}
  • 定位文件读取
  • 下载第一块
@Test
	public void download1() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
		
		//创建一个输入流,把hdfs的文件读取到内存
		FSDataInputStream open = fs.open(new Path("/user/hadoop-2.7.2.tar.gz"));
		//创建输出流,把读取进内存的数据写出到本地磁盘
		FileOutputStream fos = new FileOutputStream(new File("D:/test/part1.tar.gz"));
		
		
		byte[] b = new byte[1024];//1024字节 1kb
		for(int i=0;i < 1024*128;i++){
			open.read(b);
			fos.write(b);
		}
		
		//4 关闭资源
		IOUtils.closeStream(open);
		IOUtils.closeStream(fos);
		fs.close();			
	}
  • 下载第二块
@Test
	public void download2() throws Exception {
		//1 创建一个配置对象
		Configuration conf = new Configuration();
		//2 获取hdfs的客户端
		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop101:9000"), conf, "root");
		//3 通过客户端操作hdfs
		
		//创建一个输入流,把hdfs的文件读取到内存
		FSDataInputStream open = fs.open(new Path("/user/hadoop-2.7.2.tar.gz"));
		open.seek(128*1024*1024);//128M=128*1024kb=128*1024*1024
		//创建输出流,把读取进内存的数据写出到本地磁盘
		FileOutputStream fos = new FileOutputStream(new File("D:/test/part2.tar.gz"));
		
		IOUtils.copyBytes(open, fos, conf);
		//4 关闭资源
		IOUtils.closeStream(open);
		IOUtils.closeStream(fos);
		fs.close();			
	}
  • 合并文件
    在window命令行中执行如下命令(所在文件夹),然后修改part2文件为hadoop-2.7.2.tar.gz并解压
    type hadoop-2.7.2.tar.gz.part2 >> hadoop-2.7.2.tar.gz.part1

四、HDFS的数据流

1、HDFS写数据流程

HDFS写数据流程,如图所示:
配置用户名称
Hadoop-HDFS(详解)

(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
(2)NameNode返回是否可以上传。
(3)客户端请求第一个 block上传到哪几个datanode服务器上。
(4)NameNode返回3个datanode节点,分别为dn1、dn2、dn3。
(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
(6)dn1、dn2、dn3逐级应答客户端。
(7)客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;
(8)当一个block传输完成之后,客户端再次请求NameNode上传第二个block的服务器。(重复执行3-7步)。

2、HDFS读数据流程

HDFS的读数据流程,如图所示:
HDFS读数据流程
Hadoop-HDFS(详解)

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

五、NameNode和SecondaryNameNode工作机制

Hadoop-HDFS(详解)

1、NN和2NN工作机制

NN和2NN工作机制,如图所示
NN和2NN工作机制
Hadoop-HDFS(详解)

(1)第一阶段:NameNode启动
a)第一次启动NameNode格式化后,创建fsimageedits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
b)客户端对元数据进行增删改的请求。
c)NameNode记录操作日志,更新滚动日志。
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.chkpointNameNode
h)NameNodefsimage.chkpoint重新命名成fsimage

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是否检查结果。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中。

2、Fsimage和Edits解析

1)概念
namenode被格式化之后,将在/opt/module/hadoop-2.7.2/data/tmp/dfs/name/current目录中产生如下文件:

fsimage_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION

(1)fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件的序列化信息。
(2)edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。
(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字
(4)每次NameNode启动的时候都会将fsimage文件读入内存,并执行edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将fsimage和edits文件进行了合并。
2)oiv查看fsimage文件
(1)查看oiv和oev命令

[aaa@qq.com current]# hdfs
Oiv应用离线查看映射器,oev 应用离线编辑查看器,查看日志

oiv apply the offline fsimage viewer to an fsimage
oev apply the offline edits viewer to an edits file
(2)基本语法

hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径

(3)案例实操

[aaa@qq.com current]# pwd
/opt/module/hadoop-2.7.2/data/tmp/dfs/name/current
[aaa@qq.com current]# hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-2.7.2/fsimage.xml
[aaa@qq.com current]# cat /opt/module/hadoop-2.7.2/fsimage.xml

将显示的xml文件内容拷贝到Idea中创建的xml文件中,并格式化。部分显示结果如下。Xml参数必须大写。

<inode>
	<id>16386</id>
	<type>DIRECTORY</type>
	<name>user</name>
	<mtime>1512722284477</mtime>
	<permission>root:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16387</id>
	<type>DIRECTORY</type>
	<name>root</name>
	<mtime>1512790549080</mtime>
	<permission>root: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>root:supergroup:rw-r--r--</permission>
	<blocks>
		<block>
			<id>1073741825</id>
			<genstamp>1001</genstamp>
			<numBytes>59</numBytes>
		</block>
	</blocks>
</inode >

3)oev查看edits文件
(1)基本语法
hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
(2)案例实操

[aaa@qq.com current]# hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-2.7.2/edits.xml
[aaa@qq.com current]# cat /opt/module/hadoop-2.7.2/edits.xml

将显示的xml文件内容拷贝到Idea中创建的xml文件中,并格式化。显示结果如下。

<?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>root</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_ALLOCATE_BLOCK_ID</OPCODE>
		<DATA>
			<TXID>131</TXID>
			<BLOCK_ID>1073741839</BLOCK_ID>
		</DATA>
	</RECORD>
	<RECORD>
		<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
		<DATA>
			<TXID>132</TXID>
			<GENSTAMPV2>1016</GENSTAMPV2>
		</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>
	<RECORD>
		<OPCODE>OP_CLOSE</OPCODE>
		<DATA>
			<TXID>134</TXID>
			<LENGTH>0</LENGTH>
			<INODEID>0</INODEID>
			<PATH>/hello7.txt</PATH>
			<REPLICATION>2</REPLICATION>
			<MTIME>1512943608761</MTIME>
			<ATIME>1512943607866</ATIME>
			<BLOCKSIZE>134217728</BLOCKSIZE>
			<CLIENT_NAME></CLIENT_NAME>
			<CLIENT_MACHINE></CLIENT_MACHINE>
			<OVERWRITE>false</OVERWRITE>
			<BLOCK>
				<BLOCK_ID>1073741839</BLOCK_ID>
				<NUM_BYTES>25</NUM_BYTES>
				<GENSTAMP>1016</GENSTAMP>
			</BLOCK>
			<PERMISSION_STATUS>
				<USERNAME>root</USERNAME>
				<GROUPNAME>supergroup</GROUPNAME>
				<MODE>420</MODE>
			</PERMISSION_STATUS>
		</DATA>
	</RECORD>
</EDITS >

3、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 >

4、集群安全模式

1)概述
NameNode启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件和一个空的编辑日志。此时,NameNode开始监听DataNode请求。但是此刻,NameNode运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。
系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统的正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向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)先进入安全模式

[aaa@qq.com 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)再打开一个窗口,执行

[aaa@qq.com hadoop-2.7.2]# bin/hdfs dfsadmin -safemode leave

六、DataNode工作机制

DataNode工作机制,如图所示:
Hadoop-HDFS(详解)

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

完结,HDFS暂介绍这里,如写的哪里有问题,还望各位多多指点一二,共同学习,加油!谢谢观看。

相关标签: 大数据