大数据学习笔记-HDFS(四)——HDFS架构

news/2024/12/22 14:22:54/

1、HDFS架构

Hadoop Distribute File System,Hadoop分布式文件系统,HDFS是Hadoop核心组件之一,作为生态圈最底层的分布式服务而存在。

HDFS解决的问题就是大数据如何存储。

架构图:主从架构(master/slave)。通常包含一个主节点和多个从节点。主节点存储和管理namespace,即文件块、位置、权限、大小、其实地址等等,从节点存储文件数据块

 

1.1 角色职责、

namenode是主节点,管理文件西戎元数据信息,包括namespace目录结构、文件块位置。分布式文件系统的核心,架构中的主角色,维护管理系统元数据,包括空间目录树结构、文件和块的位置信息、访问权限。NameNode成为了HDFS的唯一入口。

NameNode内部通过内存和磁盘文件两种方式管理元数据。,内存优点速度快、缺点不能持久保存。磁盘上的元数据包括Fsimage内存元数据镜像文件和edits log(Joural)编辑日志。

Hadoop2之前,namenode是单点故障,Hadoop2中引入的高可用,集群中热备运行两个或多个Namenode。

datanode是从节点,负责存储文件具体的数据块。从角色,负责具体数据块的存储,DataNode的数量决定了HDFS集群的整体数据存储能力,通过和NameNode配合维护着数据块。

两种角色各司其职,协调完成文件存储服务

SecondaryNameNode:主角色的辅助角色,帮助主角色进行元数据的合并,(和namenode不同,也不是备份,也不能代替namenode)。守护进程,充当Namenode的辅助,不能替代NameNode,当NameNode合并Fsimage和edit log文件以还原当前文件系统的名称空间,如果edit log过大不利于加载,SecondaryNameNode就是辅助从Namenode下载Fsimage文件和edits log文件进行合并。
 

1.2 重要特性

HDFS在文件的物理上是分块存储(Block)的,块的大小可以通过配置参数来规定,参数位于hdfs-default.xml中,dfs.blocksize。默认128M

 副本机制,每一个块不是存储一份,默认存储三份,文件的所有block,默认dfs.replication 的值是3,也就是会额外在复制两个副本,可以通过配置文件修改。

Namespace:层次型文件组织结构,用户可以创建目录、保存文件,创建、删除、重命名文件。NomeNode负责维护namespace命名空间。

元数据管理:元数据两种类型(文件自身属性——名称、大小、修改时间、文件大小、复制因子、数据块大小;数据块位置映射信息:记录文件块和datanode之间的映射信息,即哪个块在那个旧机器上)。

2、HDFS Web Interface

Web Interface介绍:Hadoop还为HDFS提供了一个Web 界面,访问地址是namenode节点的机器上,端口为9870。地址形式化表示为“http://nn_host:port/”。本次学习的地址为

“http://node1:9870”,页面如下

 OverView模块:包含集群的基本信息、核心信息、总览信息。例如:安全模式、文件、文件块、堆内存大小,文件系统使用量表格(总量、使用量、剩余量、使用率)、Namedoe Joural State、NameNode Storage、DFS Storsge Types

DataNode模块:节点数,节点状态(在服务、下线、。。。)。

datanode Volume Failures模块:数据节点卷的错误信息。

Snapshot模块:快照概览、快照信息。

Start Progress模块:启动信息,启动步骤,完成率,完成时间

Utilities模块:包含了:文件浏览、日志、configuration(配置)等子模块

3、HDFS读写流程

3.1写流程

核心概念-pipeline(管道),这是HDFS在上传写数据过程中采用的一种数据传输方式。客户端将数据块写入第一个DN,第一个DN保存之后传给第二个,然后第二个DN传给第三个,。。。

管道传输顺序沿着一个方向传输,这样能够充分利用每个机器的带宽,避免

ACK(Acknowledge character)应答响应,确认字符。在数据通讯中,接收方向发送方的一种传输类控制字符,表示数据确认接收无误

HDFS pipeline管道传输数据过程中,传输反向会进行ack校验。

默认3副本存储策略。BlockPlacementPolicyDefault指定

 第一块副本:优先客户端本地,否则随机。

第二块副本:不同于第一块副本的不同机架

第三块副本:第二块副本相同机架的不同机器。

写数据的流程示意图:

 

 客户端创建FileSystem对象实例DistrubuteFIleSystem,调用其creat方法,通过RPC请求NameNode创建,NameNode检查文件是否存在,目录是否存在,权限,检查通过,返回文件数据输出流对象,客户端通过文件输出流向DN写数据,DN节点通过管道向下一个节点依次写数据,然后返回ack。客户端数据写入后,数据流关闭。

3.2 读数据流程

 客户端首先打开分布式文件系统,然后从nn上获取文件数据的元数据,然后创建文件系统数据输入流,分别从相应的DN读取数据。

客户端必须首先连接namenode,namenode是HDFS唯一访问入口

NameNode:是HDFS的核心、集群的主角色,被称为master.

NameNode仅存储HDFS的元数据:文件系统namespace操作维护目录树,文件和块

NameNode不存储世家的数据和数据集,DataNode存储

NameNode知道HDFS任何给定文件的块列表及其位子

NameNode并不持久化每个文件中各个块所在的DataNode的位置信息,这些信息会在系统启动时从DataNode中重建。

NameNode对于HDFS至关重要,Name Node关闭时,HDFS/Hadoop集群无法访问

NameNode 在Hadoop 1.0中,单点故障,2.0支持主备切换。

NameNode需要配置大内存。

DataNode职责

DataNode负责将实际数据存储在HDFS中,是集群的从脚色。

DataNode启动时,他将自己发布到NameNode,并汇报自己负责持有的块列表。

根据NameNode的指令,执行块的创建、复制、删除操作。

DataNode会定期(dfs.heartbeat.interval配置项配置,默认3s)向NameNode发送心跳,如果NameNode长时间没有接收到DataNode发送的心跳,NameNode就会任务DataNode失效。

DataNode会定期向NameNode汇报自己持有的数据块,汇报时间间隔参数

dfs.blockreport.intervalMsec,参数未配置默认6小时。

DataNode所在的机器需要大磁盘。

4、NomeNode元数据管理

元数据:为描述数据的数据(data about data)

在HDFS中,元数据主要指的是文件相关的元数据,由NameNode维护管理。

文件自身属性信息

文件名称、权限、修改时间、文件大小、复制因子、数据块大小

文件块位置映射信息

记录文件块和DataNode之间的映射信息,即哪个块位于哪个节点上。

内存元数据

内存保证用户操作比较快,NameNode把所有元数据都存储在内存中,我们叫做内存元数据,内存中的元数据是最为完整的。

内存致命问题:断电数据丢失,数据不会持久化

元数据文件

fsimage内存镜像文件,内存元数据的一个持久化检查点,但是fsimage中仅包含hadoop文件系统中的自身文件属性相关的元数据ixni,不包含文件块位置信息,文件块位置信息只保存在内存当中,启动的时候由datanode上报。文件信息持久化到磁盘,IO过程对namenode性能产生影响,一般元fsImage镜像数据文件记录不能太频繁。

Edits Log编辑日志

为了避免两次持久化之间的数据丢失,又设计了Edits Log编辑日志文件,文件中记录的是HDFS所有更改操作(创建、删除、修改),文件系统客户端的操作首先记录到edits中。

namenode 启动的时候先加载fsimage,之后再执行edits文件中的各项操作

NameNode元数据管理相关的目录文件

HDFS首次启动之前需要首先进行format操作,format之前,HDFS在物理上还不存在,其次此处format并不是格式化,而是清楚与准备工作。

namenode元数据存储目录由参数:dfs.namenode.name.dir指定,在hdfs-site.xml文件中配置。默认值为

 在core-site中查看配置的hadoop.tmp.dir值

查看

cat /export/servers/hadoop-3.1.4/etc/hadoop/core-site.xml

 hadoop.tmp.dir的值

 进入到相关目录

 

 进入到current目录,查看最终存储的目录

 Version,查看

lnamespaceID、clusterID、blockpoolID这些都是(HDFS唯一标识符,联邦架构下)

namespaceID:每个的NameNode提供唯一的命名空间,并管理一组唯一的文件块池(blockpoolID)。clusterID将整个集群结合在一起作为单个逻辑单元,在集群中的所有节点上都是一样的

fsImage文件内容查看,直接无法查看

oiv是offline image viewer的缩写,可以转为xml格式查看

命令

 hdfs oiv -i fsimage_0000000000000000515 -p XML -o fsiamge.xml

 edits log 查看

命令

hdfs oev -i edits_0000000000000000010-0000000000000000017 -o edits.xml

 SecondaryNameNode

edit logs因操作过多,记录变多而变大

fsimage因时间间隔时间长将会变旧

namenode重启会花费很长的时间,因为有很多改动需要从edit log合并到fsimage

频繁进行持久化,影响NN正常服务

SNN为了克服上述问题,合并edit log 和 fsiamge,减小edit log文件的大小和得到一个新的fsimage文件,减小NN的压力。

SNN Checkpoint 核心是把fsimage与edits log合成以生成新的fsimage的过程。

第一步:出发checkpoint操作条件时,snn发送请求给nn滚动edit log。然后nn生成新的编辑日志,

第二步:snn将旧的edit log文件和上次fsimage复制到本地合并成一个新的fsimage文件。

第三步:snn首先将fsiamge载入内存,然后一条一条执行edit文件中的操作,使得内存中的fsimage不断更新,这个过程就是edits和fsimage文件合并。合并结束,snn在内存中生成一个fsiamge,写到磁盘

第四步:snn将新的fsimage文件复制到nn节点,至此刚好是一个轮回,等待下一次checkpoint出发snn进行工作,一直这样循环操作。

checkpoint的触发条件:

hdfs-site.xml

dfs.namenode.checkpoint.period=3600  //两次连续的checkpoint之间的时间间隔。默认1小时

dfs.namenode.checkpoint.txns=1000000 //最大没有执行checkpoint事务的数量,满足将强制执行紧急checkpoint,即使尚未达到检查点周期。默认100万事务数量。

NameNode元数据恢复

(1)NameNode存储 多目录

namenode元数据存储目录参数:dfs.namenode.name.dir指定,多个目录,生成的内容相同。

可以将目录指向网络文件系统。

(2)从SNN在checkpoint的时候会将fsimage和edit logs下载到本地,checkpoint之后也不会删除。

 这个操作可以恢复部分数据,不能恢复全部数据。

(3)高可用,主备namenode。

5、小文件解决方案

Hadoop Archive文件归档

背景;HDFS不擅长存储小文件,因为每个文件最少一个block,block的元数据会占用namenode内存,小文件吃内存。

测试,生成小文件,存储到HDFS

[root@node2 ~]# echo 1 > 1.txt
[root@node2 ~]# echo 1 > 2.txt
[root@node2 ~]# echo 1 > 3.txt
[root@node2 ~]# ls
1.txt  2.txt  3.txt  anaconda-ks.cfg  core-site.xml  hdfs-site.xml  mapred-site.xml  yarn-site.xml
[root@node2 ~]# hadoop fs -mkdir /smallfile
[root@node2 ~]# hadoop fs -put 1.txt 2.txt 3.txt /smallfile

每个小文件只有2B,但是需要记录文件名、大小、块信息等元数据到NN的内存。

Archive概述:可以有效的处理以上问题,把多个文件归档成一个文件,归档后文件还可以透明的访问每一个文件。文件越多,效果越明显。

创建Archive

[root@node2 ~]# hadoop archive --help
usage: archive <-archiveName <NAME>.har> <-p <parent path>> [-r <replication factor>] <src>* <dest>-archiveName <arg>   Name of the Archive. This is mandatory option-help                Show the usage-p <arg>             Parent path of sources. This is mandatory option-r <arg>             Replication factor archive files


 -archiveName 要创建归档的文件名称,扩展名是*.har
 -p <arg>             指定文件档案文件src的相对路径
 -r <arg>             Replication factor archive files

比如:-p /foo/bar a/b/c e/f/g,这里的/foo/bara/b/ce/f/g的父路径,所以完整路径为/foo/bar/a/b/c/foo/bar/e/f/g

归档smallfile中的小文件

查看文件

[root@node2 ~]# hadoop fs -ls /smallfile 
Found 3 items
-rw-r--r--   3 root supergroup          2 2022-11-26 23:28 /smallfile/1.txt
-rw-r--r--   3 root supergroup          2 2022-11-26 23:28 /smallfile/2.txt
-rw-r--r--   3 root supergroup          2 2022-11-26 23:28 /smallfile/3.txt

启动yarn

start-yarn.sh

执行归档

 hadoop archive -archiveName  test.har -p /smallfile /outoutdir

查看归档内容

hadoop fs -ls /outputdir/test.har

查看Archive--查看归档之前的样子

在查看har文件的时候,如果没有指定访问协议,默认使用的就是hdfs://,此时所能看到的就是归档之后的样子。
此外,Archive还提供了自己的har uri访问协议。如果用har uri去访问的话,索引、标识等文件就会隐藏起来,只显示创建档案之前的原文件:
Hadoop Archives的URI是:
har://scheme-hostname:port/archivepath/fileinarchive   
scheme-hostname格式为hdfs-域名:端口

提取

#按顺序解压存档(串行):
hadoop fs -cp har:///outputdir/test.har/* /smallfile1
#要并行解压存档,请使用DistCp,对应大的归档文件可以提高效率:
hadoop distcp har:///outputdir/test.har/* /smallfile2

Sequence File

Sequence File 二进制文件,底层直接以<key, value>键值对形式序列化到文件中
优点:紧凑、支持不同级别的压缩,
三种格式:未压缩,格式 header | record|record|sync|record
基于record压缩: header | record|record(value被压缩)|sync|record
基于block块压缩:header|sync|block|sync|block(record)|block|sync|
一个header和多个record组成.
开发环境构建
<dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.1.4</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>3.1.4</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.4</version></dependency>
</dependencies>

代码

写序列化

package cn.itcast.hdfs.sequence;import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.SequenceFile;import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.GzipCodec;/*** @description:* @author: Allen Woon* @time: 2020/12/23 15:56*/
public class SequenceFileWrite {private static final String[] DATA = {"One, two, buckle my shoe","Three, four, shut the door","Five, six, pick up sticks","Seven, eight, lay them straight","Nine, ten, a big fat hen"};public static void main(String[] args) throws Exception {//设置客户端运行身份 以root去操作访问HDFSSystem.setProperty("HADOOP_USER_NAME","root");//Configuration 用于指定相关参数属性Configuration conf = new Configuration();//sequence file key、valueIntWritable key = new IntWritable();Text value = new Text();//构造Writer参数属性SequenceFile.Writer writer = null;CompressionCodec Codec = new GzipCodec();SequenceFile.Writer.Option optPath = SequenceFile.Writer.file(new Path("hdfs://node1:8020/seq.out"));SequenceFile.Writer.Option optKey = SequenceFile.Writer.keyClass(key.getClass());SequenceFile.Writer.Option optVal = SequenceFile.Writer.valueClass(value.getClass());SequenceFile.Writer.Option optCom = SequenceFile.Writer.compression(SequenceFile.CompressionType.RECORD,Codec);try {writer = SequenceFile.createWriter( conf, optPath, optKey, optVal, optCom);for (int i = 0; i < 100; i++) {key.set(100 - i);value.set(DATA[i % DATA.length]);System.out.printf("[%s]\t%s\t%s\n", writer.getLength(), key, value);writer.append(key, value);}} finally {IOUtils.closeStream(writer);}}}

读序列化

package cn.itcast.hdfs.sequence;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.ReflectionUtils;import java.io.IOException;/*** @description:* @author: Allen Woon* @time: 2020/12/23 20:27*/
public class SequenceFileRead {public static void main(String[] args) throws IOException {//设置客户端运行身份 以root去操作访问HDFSSystem.setProperty("HADOOP_USER_NAME","root");//Configuration 用于指定相关参数属性Configuration conf = new Configuration();SequenceFile.Reader.Option option1 = SequenceFile.Reader.file(new Path("hdfs://node1:8020/seq.out"));SequenceFile.Reader.Option option2 = SequenceFile.Reader.length(174);//这个参数表示读取的长度SequenceFile.Reader reader = null;try {reader = new SequenceFile.Reader(conf,option1,option2);Writable key = (Writable) ReflectionUtils.newInstance(reader.getKeyClass(), conf);Writable value = (Writable) ReflectionUtils.newInstance(reader.getValueClass(), conf);long position = reader.getPosition();while (reader.next(key, value)) {String syncSeen = reader.syncSeen() ? "*" : "";//是否返回了Sync Mark同步标记System.out.printf("[%s%s]\t%s\t%s\n", position, syncSeen, key, value);position = reader.getPosition(); // beginning of next record}} finally {IOUtils.closeStream(reader);}}}

合并小文件

package cn.itcast.hdfs.sequence;/*** @description:* @author: Allen Woon* @time: 2020/12/24 11:21*/
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;import org.apache.commons.codec.digest.DigestUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.Reader;
import org.apache.hadoop.io.SequenceFile.Writer;
import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MergeSmallFilesToSequenceFile {private Configuration configuration = new Configuration();private List<String> smallFilePaths = new ArrayList<String>();//定义方法用来添加小文件的路径public void addInputPath(String inputPath) throws Exception{File file = new File(inputPath);//给定路径是文件夹,则遍历文件夹,将子文件夹中的文件都放入smallFilePaths//给定路径是文件,则把文件的路径放入smallFilePathsif(file.isDirectory()){File[] files = FileUtil.listFiles(file);for(File sFile:files){smallFilePaths.add(sFile.getPath());System.out.println("添加小文件路径:" + sFile.getPath());}}else{smallFilePaths.add(file.getPath());System.out.println("添加小文件路径:" + file.getPath());}}//把smallFilePaths的小文件遍历读取,然后放入合并的sequencefile容器中public void mergeFile() throws Exception{Writer.Option bigFile = Writer.file(new Path("D:\\bigfile.seq"));Writer.Option keyClass = Writer.keyClass(Text.class);Writer.Option valueClass = Writer.valueClass(BytesWritable.class);//构造writerWriter writer = SequenceFile.createWriter(configuration, bigFile, keyClass, valueClass);//遍历读取小文件,逐个写入sequencefileText key = new Text();for(String path:smallFilePaths){File file = new File(path);long fileSize = file.length();//获取文件的字节数大小byte[] fileContent = new byte[(int)fileSize];FileInputStream inputStream = new FileInputStream(file);inputStream.read(fileContent, 0, (int)fileSize);//把文件的二进制流加载到fileContent字节数组中去String md5Str = DigestUtils.md5Hex(fileContent);System.out.println("merge小文件:"+path+",md5:"+md5Str);key.set(path);//把文件路径作为key,文件内容做为value,放入到sequencefile中writer.append(key, new BytesWritable(fileContent));}writer.hflush();writer.close();}//读取大文件中的小文件public void readMergedFile() throws Exception{Reader.Option file = Reader.file(new Path("D:\\bigfile.seq"));Reader reader = new Reader(configuration, file);Text key = new Text();BytesWritable value = new BytesWritable();while(reader.next(key, value)){byte[] bytes = value.copyBytes();String md5 = DigestUtils.md5Hex(bytes);String content = new String(bytes, Charset.forName("GBK"));System.out.println("读取到文件:"+key+",md5:"+md5+",content:"+content);}}public static void main(String[] args) throws Exception {MergeSmallFilesToSequenceFile msf = new MergeSmallFilesToSequenceFile();//合并小文件
//		msf.addInputPath("D:\\datasets\\smallfile");
//		msf.mergeFile();//读取大文件msf.readMergedFile();}
}


http://www.ppmy.cn/news/517449.html

相关文章

4. 参数配置

4. 参数配置 参数 查看参数 show parameter parameter_name;查看参数是静态参数还是动态参数 select name,value,isses_modifiable,issys_modifiable from v$system_parameter;-- isses_modifiable 和issys_modifiable 分别对应的是session级别修改的参数和system级别修改…

python函数的4种参数类型

总结 python 函数中的不同参数类型的使用方法。 在调用函数时&#xff0c;通常会传递参数&#xff0c;函数内部的代码保持不变&#xff0c;针对 不同的参数 处理 不同的数据。 有位置传参、关键字传参、默认值参数、多值参数等。 1、参数传递 形参和实参&#xff1a; 形参&…

Python 函数的4种参数

Python的函数参数有4种&#xff1a; 必选参数&#xff1a;函数调用时必须赋值的参数默认参数&#xff1a;函数定义时&#xff0c;赋予默认值的参数&#xff0c;位于必选参数之后。如def test(param,default3),default为默认参数&#xff0c;函数调用时&#xff0c;如果没有给d…

华为webview打不开页面【型号:HUAWEI 麦芒4 】

问题描述&#xff1a;webview打开一个页面后再打开第二个页面&#xff0c;首次可以打开&#xff0c;接下来所有webview界面都打不开 问题解决&#xff1a;是系统webview的问题&#xff0c;到华为应用市场搜索webview安装即可&#xff0c;手机华为市场可能找不到&#xff0c;到电…

android 手机安装windows7,手机怎么安装win7系统 安卓手机装win7系统教程

现在少了什么都能少了手机&#xff0c;通信&#xff0c;社交&#xff0c;购物&#xff0c;查资料&#xff0c;手机功能越来越强大&#xff0c;大家都随身携带。但是手机也是有限制的&#xff0c;我们办公的时候还是会使用电脑。不过有些小伙伴也想享受一下手机当电脑用的感觉&a…

vivo7.0系统怎么无root激活XPOSED框架的教程

在异常多企业的引流&#xff0c;或业务操作中&#xff0c;理论上需要使用安卓的黑技术XPOSED框架&#xff0c;几天前&#xff0c;我们企业采购了一批新的vivo7.0系统&#xff0c;理论上都是基于7.0以上版本&#xff0c;理论上不能够获取root权限&#xff0c;虽说有一些能但比较…

vivo7.0系统手机最完美激活Xposed框架的教程

对于喜欢研究手机的机友而言&#xff0c;常常会玩到XPOSED框架及其各类功能彪悍的模块&#xff0c;对于5.0以下的系统版本&#xff0c;只要手机能获得root权限&#xff0c;安装和激活XPOSED框架是异常简易的&#xff0c;但随着系统版本的更新&#xff0c;5.0以后的系统&#xf…

android 桌面操作系统,Android主题美化: Win7桌面完成版Android Seven Pro V2

您是否只是不习惯使用Android平板电脑来操作桌面&#xff0c;还是对Android随附的桌面感到厌倦&#xff0c;是否想要更改为其他Android主题&#xff1f;今天的平板电脑包装盒为您带来了一个Android桌面美化软件&#xff0c;该软件将Android主题修改为Windows7: Android Seven P…