Hadoop-HDFS(详解)
大家好,我是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组成架构如图所示:
架构主要由四个部分组成,分别为HDFS Client、NameNode、DataNode和Secondary 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)定期合并fsimage和Edits,并推送给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),如图所示:
2)配置HADOOP_HOME环境变量,如图所示:
3)配置Path环境变量,如图所示:
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写数据流程,如图所示:
配置用户名称
(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读数据流程
(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)。
(4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件(并行,快)。
五、NameNode和SecondaryNameNode工作机制
1、NN和2NN工作机制
NN和2NN工作机制,如图所示
NN和2NN工作机制
(1)第一阶段:NameNode启动
a)第一次启动NameNode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
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.chkpoint到NameNode。
h)NameNode将fsimage.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工作机制,如图所示:
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
完结,HDFS暂介绍这里,如写的哪里有问题,还望各位多多指点一二,共同学习,加油!谢谢观看。
上一篇: leetcode28:Implement strStr()
下一篇: javaEE常见错误