这篇文章给大家分享的是有关HDFS体系结构中有哪几类节点的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
HDFS体系结构中有两类节点,一类是NameNode,又叫"元数据节点";另一类是DataNode,又叫"数据节点"。这两类节点分别承担Master和Worker具体任务的执行节点。
1)元数据节点用来管理文件系统的命名空间
其将所有的文件和文件夹的元数据保存在一个文件系统树中。
这些信息也会在硬盘上保存成以下文件:命名空间镜像(namespace image)及修改日志(edit log)
其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而这些信息并不存储在硬盘上,而是在系统启动的时候从数据节点收集而成的。
2)数据节点是文件系统中真正存储数据的地方。
客户端(client)或者元数据信息(namenode)可以向数据节点请求写入或者读出数据块。
其周期性的向元数据节点回报其存储的数据块信息。
3)从元数据节点(secondary namenode)
从元数据节点并不是元数据节点出现问题时候的备用节点,它和元数据节点负责不同的事情。
其主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。这点在下面会相信叙述。
合并过后的命名空间镜像文件也在从元数据节点保存了一份,以防元数据节点失败的时候,可以恢复。
VERSION文件是java properties文件,保存了HDFS的版本号。
namespaceID=1232737062
cTime=0
storageType=NAME_NODE
layoutVersion=-18
HDFS是一个主/从(Mater/Slave)体系结构,从最终用户的角度来看,它就像传统的文件系统一样,可以通过目录路径对文件执行CRUD(Create、Read、Update和Delete)操作。但由于分布式存储的性质,HDFS集群拥有一个NameNode和一些DataNode。NameNode管理文件系统的元数据,DataNode存储实际的数据。客户端通过同NameNode和DataNodes的交互访问文件系统。客户端联系NameNode以获取文件的元数据,而真正的文件I/O操作是直接和DataNode进行交互的。
图5-1-1 列出HDFS文件
2)列出HDFS目录下某个文档中的文件
此处为你展示如何通过"-ls 文件名"命令浏览HDFS下名为"input"的文档中文件:
hadoop fs –ls input
执行结果如图5-1-2所示。
图5-1-3 成功上传file到HDFS
4)将HDFS中文件复制到本地系统中
此处为你展示如何通过"-get 文件1 文件2"命令将HDFS中的"output"文件复制到本地系统并命名为"getout"。
hadoop fs –get output getout
执行结果如图5-1-4所示。
图5-1-5 成功删除HDFS下的newoutput文档
6)查看HDFS下某个文件
此处为你展示如何通过"-cat 文件"命令查看HDFS下input文件中内容:
hadoop fs -cat input/*
执行结果如图5-1-6所示。
图5-2-1 HDFS基本统计信息
2)退出安全模式
NameNode在启动时会自动进入安全模式。安全模式是NameNode的一种状态,在这个阶段,文件系统不允许有任何修改。安全模式的目的是在系统启动时检查各个DataNode上数据块的有效性,同时根据策略对数据块进行必要的复制或删除,当数据块最小百分比数满足的最小副本数条件时,会自动退出安全模式。
系统显示"Name node is in safe mode",说明系统正处于安全模式,这时只需要等待17秒即可,也可以通过下面的命令退出安全模式:
hadoop dfsadmin –safemode enter
成功退出安全模式结果如图5-2-2所示。
图5-2-3 进入HDFS安全模式
4)添加节点
可扩展性是HDFS的一个重要特性,向HDFS集群中添加节点是很容易实现的。添加一个新的DataNode节点,首先在新加节点上安装好Hadoop,要和NameNode使用相同的配置(可以直接从NameNode复制),修改"/usr/hadoop/conf/master"文件,加入NameNode主机名。然后在NameNode节点上修改"/usr/hadoop/conf/slaves"文件,加入新节点主机名,再建立到新加点无密码的SSH连接,运行启动命令:
start-all.sh
5)负载均衡
HDFS的数据在各个DataNode中的分布肯能很不均匀,尤其是在DataNode节点出现故障或新增DataNode节点时。新增数据块时NameNode对DataNode节点的选择策略也有可能导致数据块分布的不均匀。用户可以使用命令重新平衡DataNode上的数据块的分布:
start-balancer.sh
执行命令前,DataNode节点上数据分布情况如图5-2-4所示。
执行负载均衡命令如图5-2-6所示。
图6-1-1 运行结果(1)
2)项目浏览器
图6-1-3 运行结果(3)
通过"FileSystem.create(Path f)"可在HDFS上创建文件,其中f为文件的完整路径。具体实现如下:
package com.hebut.file;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CreateFile {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
byte[] buff="hello hadoop world!\n".getBytes();
Path dfs=new Path("/test");
FSDataOutputStream outputStream=hdfs.create(dfs);
outputStream.write(buff,0,buff.length);
}
}
运行结果如图6-2-1和图6-2-2所示。
1)项目浏览器
图6-2-2 运行结果(2)
通过"FileSystem.mkdirs(Path f)"可在HDFS上创建文件夹,其中f为文件夹的完整路径。具体实现如下:
package com.hebut.dir;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CreateDir {
public static void main(String[] args) throws Exception{
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path dfs=new Path("/TestDir");
hdfs.mkdirs(dfs);
}
}
运行结果如图6-3-1和图6-3-2所示。
1)项目浏览器
图6-3-2 运行结果(2)
通过"FileSystem.rename(Path src,Path dst)"可为指定的HDFS文件重命名,其中src和dst均为文件的完整路径。具体实现如下:
package com.hebut.file;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class Rename{
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path frpaht=new Path("/test"); //旧的文件名
Path topath=new Path("/test1"); //新的文件名
boolean isRename=hdfs.rename(frpaht, topath);
String result=isRename?"成功":"失败";
System.out.println("文件重命名结果为:"+result);
}
}
运行结果如图6-4-1和图6-4-2所示。
1)项目浏览器
图6-4-2 运行结果(2)
通过"FileSystem.delete(Path f,Boolean recursive)"可删除指定的HDFS文件,其中f为需要删除文件的完整路径,recuresive用来确定是否进行递归删除。具体实现如下:
package com.hebut.file;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class DeleteFile {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path delef=new Path("/test1");
boolean isDeleted=hdfs.delete(delef,false);
//递归删除
//boolean isDeleted=hdfs.delete(delef,true);
System.out.println("Delete?"+isDeleted);
}
}
运行结果如图6-5-1和图6-5-2所示。
1)控制台结果
图6-5-2 运行结果(2)
同删除文件代码一样,只是换成删除目录路径即可,如果目录下有文件,要进行递归删除。
通过"FileSystem.exists(Path f)"可查看指定HDFS文件是否存在,其中f为文件的完整路径。具体实现如下:
package com.hebut.file;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class CheckFile {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path findf=new Path("/test1");
boolean isExists=hdfs.exists(findf);
System.out.println("Exist?"+isExists);
}
}
运行结果如图6-7-1和图6-7-2所示。
1)控制台结果
图6-7-2 运行结果(2)
通过"FileSystem.getModificationTime()"可查看指定HDFS文件的修改时间。具体实现如下:
package com.hebut.file;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class GetLTime {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
FileSystem hdfs=FileSystem.get(conf);
Path fpath =new Path("/user/hadoop/test/file1.txt");
FileStatus fileStatus=hdfs.getFileStatus(fpath);
long modiTime=fileStatus.getModificationTime();
System.out.println("file1.txt的修改时间是"+modiTime);
}
}
运行结果如图6-8-1所示。
图6-9-1 运行结果(1)
2)项目浏览器
图6-10-1 运行结果(1)
2)项目浏览器
图6-11-1 控制台结果
写入文件的过程比读取较为复杂:
1)解释一
2)解释二
使用HDFS提供的客户端开发库,向远程的Namenode发起RPC请求;
Namenode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会为文件创建一个记录,否则会让客户端抛出异常;
当客户端开始写入文件的时候,开发库会将文件切分成多个packets,并在内部以"data queue"的形式管理这些packets,并向Namenode申请新的blocks,获取用来存储replicas的合适的datanodes列表,列表的大小根据在Namenode中对replication的设置而定。
开始以pipeline(管道)的形式将packet写入所有的replicas中。开发库把packet以流的方式写入第一个datanode,该datanode把该packet存储之后,再将其传递给在此pipeline中的下一个datanode,直到最后一个datanode,这种写数据的方式呈流水线的形式。
最后一个datanode成功存储之后会返回一个ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",成功收到datanode返回的ack packet后会从"ack queue"移除相应的packet。
如果传输过程中,有某个datanode出现了故障,那么当前的pipeline会被关闭,出现故障的datanode会从当前的pipeline中移除,剩余的block会继续剩下的datanode中继续以pipeline的形式传输,同时Namenode会分配一个新的datanode,保持replicas设定的数量。
关闭pipeline,将ack queue中的数据块放入data queue的开始。
当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。
失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。
元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。
客户端调用create()来创建文件
DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件。
元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
DistributedFileSystem返回DFSOutputStream,客户端用于写数据。
客户端开始写入数据,DFSOutputStream将数据分成块,写入data queue。
Data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。
Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
如果数据节点在写入的过程中失败:
当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。
使用HDFS提供的客户端开发库,向远程的Namenode发起RPC请求;
Namenode会视情况返回文件的部分或者全部block列表,对于每个block,Namenode都会返回有该block拷贝的datanode地址;
客户端开发库会选取离客户端最接近的datanode来读取block;
读取完当前block的数据后,关闭与当前的datanode连接,并为读取下一个block寻找最佳的datanode;
当读完列表的block后,且文件读取还没有结束,客户端开发库会继续向Namenode获取下一批的block列表。
读取完一个block都会进行checksum验证,如果读取datanode时出现错误,客户端会通知Namenode,然后再从下一个拥有该block拷贝的datanode继续读。
客户端(client)用FileSystem的open()函数打开文件。
DistributedFileSystem用RPC调用元数据节点,得到文件的数据块信息。
对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。
DistributedFileSystem返回FSDataInputStream给客户端,用来读取数据。
客户端调用stream的read()函数开始读取数据。
DFSInputStream连接保存此文件第一个数据块的最近的数据节点。
Data从数据节点读到客户端(client)。
当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
失败的数据节点将被记录,以后不再连接。
利用SequenceFile、MapFile、Har等方式归档小文件,这个方法的原理就是把小文件归档起来管理,HBase就是基于此的。对于这种方法,如果想找回原来的小文件内容,那就必须得知道与归档文件的映射关系。
横向扩展,一个Hadoop集群能管理的小文件有限,那就把几个Hadoop集群拖在一个虚拟服务器后面,形成一个大的Hadoop集群。google也是这么干过的。
多Master设计,这个作用显而易见了。正在研发中的GFS II也要改为分布式多Master设计,还支持Master的Failover,而且Block大小改为1M,有意要调优处理小文件啊。
附带个Alibaba DFS的设计,也是多Master设计,它把Metadata的映射存储和管理分开了,由多个Metadata存储节点和一个查询Master节点组成。
Client向NameNode发起文件读取的请求。
NameNode返回文件存储的DataNode的信息。
Client读取文件信息。
Client向NameNode发起文件写入的请求。
NameNode根据文件大小和文件块配置情况,返回给Client它所管理部分DataNode的信息。
Client将文件划分为多个Block,根据DataNode的地址信息,按顺序写入到每一个DataNode块中。
NameNode可以看作是分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等。NameNode会将文件系统的Meta-data存储在内存中,这些信息主要包括了文件信息、每一个文件对应的文件块的信息和每一个文件块在DataNode的信息等。
DataNode是文件存储的基本单元,它将Block存储在本地文件系统中,保存了Block的Meta-data,同时周期性地将所有存在的Block信息发送给NameNode。
Client就是需要获取分布式文件系统文件的应用程序。
从元数据节点通知元数据节点生成新的日志文件,以后的日志都写到新的日志文件中。
从元数据节点用http get从元数据节点获得fsimage文件及旧的日志文件。
从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。
从元数据节点奖新的fsimage文件用http post传回元数据节点
元数据节点可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),然后更新fstime文件,写入此次checkpoint的时间。
这样元数据节点中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变的很大了。
当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit log)
元数据节点在内存中保存了文件系统的元数据信息。在记录了修改日志后,元数据节点则修改内存中的数据结构。
每次的写操作成功之前,修改日志都会同步(sync)到文件系统。
fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在硬盘上直接修改。
同数据的机制相似,当元数据节点失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,然后逐一重新执行修改日志中的操作。
从元数据节点就是用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上的
checkpoint的过程如下:
blk_<id>保存的是HDFS的数据块,其中保存了具体的二进制数据。
blk_<id>.meta保存的是数据块的属性信息:版本信息,类型信息,和checksum
当一个目录中的数据块到达一定数量的时候,则创建子文件夹来保存数据块及数据块属性信息。
数据节点的VERSION文件格式如下:
layoutVersion是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
namespaceID是文件系统的唯一标识符,是在文件系统初次格式化时生成的。
cTime此处为0
storageType表示此文件夹中保存的是元数据节点的数据结构。
感谢各位的阅读!关于“HDFS体系结构中有哪几类节点”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。