HDFS(Hadoop Distributed File System)称为Hadoop分布式文件系统,以流式数据访问模式来存储超大文件,运行于商用硬件集群上,是管理网络中跨多台计算机存储的文件系统。
HDFS不适合用在:要求低时间延迟数据访问的应用,存储大量的小文件,多用户写入,任意修改文件。
1.块Block
HDFS数据块:HDFS上的文件被划分为块大小的多个分块,作为独立的存储单元,称为数据块,默认大小是128MB。
使用数据块的好处是:
- 一个文件的大小可以大于网络中任意一个磁盘的容量。文件的所有块不需要存储在同一个磁盘上,因此它们可以利用集群上的任意一个磁盘进行存储。
- 简化了存储子系统的设计,将存储子系统控制单元设置为块,可简化存储管理,同时元数据就不需要和块一同存储,用一个单独的系统就可以管理这些块的元数据。
- 数据块适合用于数据备份进而提供数据容错能力和提高可用性。
2.HDFS数据存储机制
Namenode
Namenode 的目录结构:
${ dfs.name.dir}/current /VERSION
/edits
/fsimage
/fstime
dfs.name.dir 是 hdfs-site.xml 里配置的若干个目录组成的列表。
Namenode 上保存着 HDFS 的命名空间。对于任何对文件系统元数据产生修改的操作, Namenode 都会使用一种称为 EditLog 的编辑日志文件记录下来。例如,在 HDFS 中创建一个文件, Namenode 就会在 Editlog 中插入一条记录来表示;同样地,修改文件的副本系数也将往 Editlog 插入一条记录。 Namenode 在本地操作系统的文件系统中存储这个 Editlog 。整个文件系统的名 字空间,包括数据块到文件的映射、文件的属性等,都存储在一个称为 FsImage 的命名空间镜像文件中,这 个文件也是放在 Namenode 所在的本地文件系统上。
Namenode 在内存中保存着整个文件系统的名字空间和文件数据块映射 (Blockmap) 的映像 。这个关键的元数据结构设计得很紧凑,因而一个有 4G 内存的 Namenode 足够支撑大量的文件 和目录。当 Namenode 启动时,它从硬盘中读取 Editlog 和 FsImage ,将所有 Editlog 中的事务作 用在内存中的 FsImage 上,并将这个新版本的 FsImage 从内存中保存到本地磁盘上,然后删除 旧的 Editlog ,因为这个旧的 Editlog 的事务都已经作用在 FsImage 上了。这个过程称为一个检查 点 (checkpoint) 。在当前实现中,检查点只发生在 Namenode 启动时,在不久的将来将实现支持 周期性的检查点。
HDFS NameSpace
HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目 录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数 现有的文件系统类似:用户可以创建、删除、移动或重命名文件。当前, HDFS 不支持用户磁盘配额和访问权限控制,也不支持硬链接和软链接。但 是 HDFS 架构并不妨碍实现这些特性。
Namenode 负责维护文件系统命名空间,任何对文件系统名字空间或属 性的修改都将被 Namenode 记录下来。应用程序可以设置 HDFS 保存的文件 的副本数目。文件副本的数目称为文件的副本系数,这个信息也是由 Namenode 保存的。
DataNode
Datanode 将 HDFS 数据以文件的形式存储在本地的文件系统中,它并不知道有 关 HDFS 文件的信息。它把每个 HDFS 数据块存储在本地文件系统的一个单独的文件 中。 Datanode 并不在同一个目录创建所有的文件,实际上,它用试探的方法来确定 每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所 有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目 录中支持大量的文件。
当一个 Datanode 启动时,它会扫描本地文件系统,产生一个这些本地文件对应 的所有 HDFS 数据块的列表,然后作为报告发送到Namenode ,这个报告就是块状态 报告。
NameNode与DataNode的工作机制
(2019.03.28更新)
NameNode工作机制:
1.第一次启动:第一次启动都需要格式化nameNode ,创建fsimage,edits. 第一次启动只需要加载fsiamge。
2.如果不是第一次启动: 直接加载edits ,fsimage镜像文件 ,合并成一个新的fsimage 文件,再创建edits 文件记录新的操作行为。
启动的过程中,会存在30秒钟等待时间 ,这个等待的时间就是安全模式。
补充一下HDFS的安全模式。它是指,在系统的正常操作期间,namonode会在内存中保留所有块位置的映射信息。在安全模式下,各个datanode会向namenode发送最新的块列表信息,namenode了解到足够多的块位置信息后,即可高效运行文件系统。
DataNode工作机制:
文字描述:
1.一个数据块在datanode上是以文件形式存储在磁盘上的,包括了两个文件,一个数据本身,一个是元数据包 包括数据块的长度,,数据块的校验和,由于HDFS上的数据是不允许被重复上传的所以在上传之前会对上传的数据进行检查 ,时间戳。
2.DataNode启动后会向nameNode进行注册,通过后,会周期性的向namenode上报自己的datanode上的块信息。
3.心跳报告,每3秒钟向nameNode进行汇报,心跳的返回结果中带有NameNode 带给该datanode复制数据块,移动数据块的命令, 如果说超过了10分钟datanode没有响应 ,则就会认为这个datanode节点不可用,会选择其他的机器。
Secondary NameNode
Secondary NameNode 定期合并 fsimage 和 edits 日志,将 edits 日志文件大小控制在一个限度下。
如果NameNode意外终止,secondaryNameNode的工作是什么?它是如何工作的?
注意,secondaryNameNode
1.并非NameNode的热备;
2.辅助NameNode,分担其工作量;
3.定期合并fsimage和edits,推送给NameNode;
4.在紧急情况下,可辅助恢复NameNode。
简单概括:
Namenode:HDFS的守护进程,用来管理文件系统的命名空间,负责记录文件是如何分割成数据块,以及这些数据块分别被存储到那些数据节点上,它的主要功能是对内存及IO进行集中管理。
Datanode:文件系统的工作节点,根据需要存储和检索数据块,并且定期向namenode发送他们所存储的块的列表。
Secondary Namenode:辅助后台程序,与NameNode进行通信,以便定期保存HDFS元数据的快照。
(2019.04.10 更新)
secondary namenode工作机制
1)第一阶段:namenode启动
(1)第一次启动namenode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求
(3)namenode记录操作日志,更新滚动日志。
(4)namenode在内存中对数据进行增删改查
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问namenode是否需要checkpoint。直接带回namenode是否检查结果。
(2)Secondary NameNode请求执行checkpoint。
(3)namenode滚动正在写的edits日志
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint
(7)拷贝fsimage.chkpoint到namenode
(8)namenode将fsimage.chkpoint重新命名成fsimage
NameNode与Secondary NameNode 的区别与联系?
1)机制流程同上;
2)区别
(1)NameNode负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。
(2)SecondaryNameNode主要用于定期合并命名空间镜像和命名空间镜像的编辑日志。
3)联系:
(1)SecondaryNameNode中保存了一份和namenode一致的镜像文件(fsimage)和编辑日志(edits)。
(2)在主namenode发生故障时(假设没有及时备份数据),可以从SecondaryNameNode恢复数据。
块缓存
(2020.1.15 更新)
3.HDFS的文件读写流程
文件读取流程
步骤:
•使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;
• Namenode会视情况返回文件的部分或者全部block列表,对于每个block,Namenode都会返回有该block拷贝的DataNode地址;
•客户端开发库Client会选取离客户端最接近的DataNode来读取block;如果客户端本身就是DataNode,那么将从本地直接获取数据.
•读取完当前block的数据后,关闭与当前的DataNode连接,并为读取下一个block寻找最佳的DataNode;
•当读完列表的block后,且文件读取还没有结束,客户端开发库会继续向Namenode获取下一批的block列表。当客户端Client完成读取时,就对FSInputStream调用close()方法。
这里补充一下关于RPC(远程过程调用)
远程过程指的不是同一个进程的调用。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
不能直接拿到远程机器的服务实例:比如loginController拿不到另一台主机loginService的实例,需要远程调用。一种实现:如Soap(http+xml)
- RPC至少有两个过程。调用方(client),被调用方(server)。
- client主动发起请求,调用指定ip和port的server中的方法,把调用结果返回给client。
- 客户端调用服务端的方法,意味着调用服务端的对象中的方法。
- 如果服务端的对象允许客户端调用,那么这个对象必须实现接口。
- 如果客户端能够调用到服务端对象的方法,那么这些方法一定位于对象的接口中。
- RPC是hadoop构建的基础。
文件写入流程
步骤:
•使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;
•Namenode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会为文件 创建一个记录,否则会让客户端抛出异常;
•当客户端开始写入文件的时候,会将文件切分成多个数据包packets,并在内部以数据队列"data queue"的形式管理这些packets,并向Namenode申请新的blocks,获取用来存储replicas的合适的datanodes列表,列表的大小根据在Namenode中对replication的设置而定。
•开始以pipeline(管道)的形式将packet写入所有的副本中。把packet以流的方式写入第一个datanode,该datanode把该packet存储之后,再将其传递给在此pipeline中的下一个datanode,直到最后一个datanode,这种写数据的方式呈流水线的形式。
•最后一个datanode成功存储之后会返回一个确认队列 ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",成功收到datanode返回的ack packet后会从"ack queue"移除相应的packet。
客户端完成数据的写入后,对数据流调用close()方法。该操作将剩余的所有数据包写入datanode pipeline,并在联系到NameNode告知其文件写入完成之前,等待确认。
4.HDFS的多副本机制
我们知道hadoop做大数据是在大量廉价的机器上用于数据存储 数据计算 数据分析。为了防止集群中某台机器出现故障而挂掉 丢失数据,HDFS内部采用多副本机制来保存数据。
replication factor:副本系数,副本因子。
特点
1. 数据类型单一
2. 副本数比较多
3. 写文件时副本的放置方法
4. 动态的副本创建策略
5. 弱化的副本一致性要求
在《Hadoop权威指南》中的副本默认方式:
- 第一个复本会随机选择,但是不会选择存储过满的节点。
- 第二个复本放在和第一个复本不同且随机选择的机架上。
- 第三个和第二个放在同一个机架上的不同节点上。
- 剩余的副本就完全随机节点了。
5.HDFS shell的简单使用:
在hadoop成功启动之后,内部提供了shell接口,可以进行命令行操作。HDFS命令行的使用和Linux Shell十分相似,这对于初学者来说是件好事。以下写出常用的命令,具体读者可以自行上机测试,比较简单:
1.hadoop namenode -format #格式化namenode
2.hadoop fs -ls / #打印 / 目录文件列表
3.hadoop fs -mkdir /input #创建目录 input
4. hadoop fs -rm /test/README.txt #hadoop删除文件README.txt
5.hadoop fs -put hadoop-env.sh input/ #上传文件 hadoop-env.sh 到 input 目录下
6.hadoop fs -cat /test/README.txt 查看test文件夹下面README.txt的内容
7.hadoop fs -get input/abc.sh hadoop-envcomp.sh #从 input 目录中下载文件
8.使用hadoop dfsadmin -report命令查看磁盘使用情况
9.hadoop fs -ls -R / :递归查看所有文件夹和文件
HDFS的文件访问权限:只读权限(r),写入权限(w),可执行权限(x)
6.HDFS JavaAPI使用
我们都知道Hadoop的源码是用java开发的,学习HDFS时 我们学会了利用HDFS shell进行简单的增删查改文件和文件目录,我们还经常利用java api写一个小demo进行HDFS操作。学习之前,我们应该学会利用window本地的java IDE集成linux系统上的hadoop环境,在这里请参考Windows下使用Eclipse工具搭建Hadoop2.6.4开发环境,进行有关配置,这里对此不再多说。
1 创建文件夹
@Test
public void mkdir() throws Exception{
fileSystem.mkdirs(new Path("/hdfsapi/test1")); //在根目录下创建文件夹
}
2 创建文件
@Test
public void create() throws Exception{
FSDataOutputStream output=fileSystem.create(new Path("/hdfsapi/test/a.txt"));
//数据流对象保存文件创建的路径
output.write("hello ching,hello china".getBytes());
output.flush();
output.close();
}
3. 查看hadoop中特定文件下的内容
@Test
public void cat() throws Exception{
FSDataInputStream input=fileSystem.open(new Path("/hdfsapi/test/a.txt"));
IOUtils.copyBytes(input,System.out,1024);
input.close();
}
4.文件上传到hdfs
@Test
public void upload() throws Exception{
Path local=new Path("D:\\test.txt"); //本地路径
Path remote=new Path("/hdfsapi/test"); //hadoop路径
fileSystem.copyFromLocalFile(local, remote);
System.out.println("文件上传成功~");
}
这里顺便说一下,文件上传到HDFS 当eclipse集成hadoop环境后,可以直接右击DFS Location下的对应hadoop文件 也可以上传windows本地的文件到HDFS中。
5.文件从hdfs下载到本地
@Test
public void download() throws Exception{
Path local=new Path("G:\\test.txt");
Path remote=new Path("/hdfsapi/test/b.txt");
fileSystem.copyToLocalFile(remote,local);
System.out.println("文件下载成功~");
}
同4,也可以直接右击从hdfs上下载文件到本地。
6.文件重命名
@Test
public void rename() throws Exception{
Path oldPath =new Path("/hdfsapi/test/a.txt");
Path newPath =new Path("/hdfsapi/test/b.txt");
fileSystem.rename(oldPath, newPath);
}
7.查看某个目录下的所有文件
@Test
public void listFiles() throws Exception{
FileStatus[] file=fileSystem.listStatus(new Path("/hdfsapi/test"));
for(FileStatus f:file){
String isDir=f.isDirectory()?"文件夹":"文件"; //判断是否为文件夹
short replication=f.getReplication(); //得到其副本信息
long len=f.getLen(); //文件大小
String path=f.getPath().toString(); //得到文件完整路径
System.out.println(isDir+"\t"+replication+"\t"+len+"\t"+path);
}
}
8.删除文件
@Test
public void delete() throws Exception{
fileSystem.delete(new Path("/hdfsapi/test/b.txt"));
}
以上的代码。是在eclipse集成hadoop环境后,通过建立maven project管理。如果以上代码没有运行成功,可下载hdfs javaAPI完整demo,不知道为啥我没找到下载积分选择0的,1积分处理吧。
参考文献: