HDFS架构和原理
Posted Java软件编程之家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDFS架构和原理相关的知识,希望对你有一定的参考价值。
HDFS版本
Hdfs的版本基本是对应hadooop的版本,了解hadoop的版本历程简介也就是了解HDFS的版本历程,简而言之,hadoop的大版本历程如下:
Hadoop1.x
Hadoop2.x
Hadoop3.x
其中hadoop2.x是目前大部分企业在使用的版本,hadoop1.x基本很少新项目会考虑使用这个版本,hadoop3.x是未来更多新项目会考虑使用的一个版本,这里要注意,不同的hadoop版本存在蛮大的区别,在我们查阅网络资料或官方文档时都要额外注意,要找到对于的版本进行学习。在没有特别版本说明的情况下,本人编写任何关于hadoop的文章都是基于hadoop3进行的。
理解hadoop平台
怎么去理解hadoop平台,为什么一提到大数据大多数开发都知道有个hadoop平台,首先我们来访问最新hadoop官方文档的网站:
https://hadoop.apache.org
我们重点关注Modules部分,可以看到,其实hadoop核心也就只有5个模块:
Hadoop Common: 支持其他Hadoop模块的公共应用程序
Hadoop Distributed File System (HDFS™): 分布式文件系统
Hadoop YARN: 工作调度和集群资源管理框架
Hadoop MapReduce: 基于YARN的一个计算框架
Hadoop Ozone: 对象存储框架
其实真正使用最多的只有3个:
HDFS
YARN
MAPREDUCE
为什么hadoop底层只有这3个模块就可以打遍天下,号称为hadoop平台呢?原因在于:hadoop率先提供了大数据需要的底层基础组件HDFS存储、YARN资源管理和调度、MR离线计算,后来的其它框架基本都是基于这3个进行封装的,例如hive、hbase、spark等。
HDFS架构和原理
先扔一张hadoop官方提供的HDFS的架构图:
这个图基本诠释了HDFS的整体架构和原理,理解这个图基本就理解了HDFS的原理,下面我们就基于这个架构图来展开分析HDFS的架构和原理。
Blocks(块)
HDFS是为了解决大数据存储的一个hadoop组件,大数据的特点就是数据量大,这就有可能出现单个文件就达到TB级别,那么现在我们思考一个问题,一个1TB的文件,如何在现有常规的服务器保存?
HDFS是这么去解决这个问题的,首先做大数据存储一台服务器肯定是不够的,所以需要集群很多的服务器组成一个逻辑上的大磁盘进行存储,将任何需要存储的文件物理切割为固定大小的块,块的大小可以配置(dfs.blocksize),默认是128M(hadoop1.x默认是64M),这些块散落分布在1台或多台服务器节点上,这就解决了单个TB级别文件的存储问题。
块大小的配置很有讲究,配置太小,会增加磁盘寻址开销,同时会增加NameNode的内存消耗,这点后面会讲到。那么问题来了,如果我们存储都是小文件比如几十MB,那么一个块就128M,会不会存在磁盘浪费的情况呢?根据Hadoop权威指南给出的说法是这样的:
当一个1MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB。
注意:
1、同一个文件块大小是相同的(最后一个块除外),不同的文件块大小可以不相同。
2、文件内容只能写入一次,写入后不能修改,但是可以追加。
3、由于文件按配置块大小被物理切分,那么就存在数据完整性问题,比如hello因为单词的hel和lo分别被切分都两个块中,为了保证读取数据的完整性,mapreduce解决方式是每开始读取一个块时,都跳过第一行数据,而每个块读取结束时,都会继续读取第二个块的第一行。
4、块在磁盘中以一个个小文件的方式进行保存。保存的目录是由块所在节点自动确定和创建的。
名称节点(NameNode)和数据节点(DataNode)
HDFS集群中有两个核心角色:DataNode和NameNode,HDFS集群实际上也是一主(NameNode)多从(DataNode)的架构。DataNode角色的节点是真正存放块(block)数据的节点,当DataNode启动时,它将扫描其本地文件系统,生成与每个本地文件相对应的所有HDFS数据块的列表,并将此报告发送到NameNode。该报告称为Blockreport。
NameNode管理文件系统的命名空间,它维护着文件系统树及整棵树内所有的文件和目录,
这些信息通过:命名空间镜像文件和编辑日志文件两种方式被永久保存在NameNode节点服务器磁盘上面。其中命名空间镜像文件保存整个文件系统的目录树,编辑日志文件记录文件系统元数据发生的所有更改。
另外NameNode内存中还保存着DataNode上报的每个文件中各个块所在的数据节点信息,为了提升NameNode的被访问效率,同时会定期从磁盘加载命名空间到内存中保存一份内存镜像,当客户端需要读取某个文件数据时,首先访问NameNode,从NameNode内存读取文件块列表或块对应的DataNode列表,然后再访问块对应的DataNode直接从DataNode中读取数据。
如果NameNode不可用,那么等同于整个HDFS文件系统不可用,如果NameNode由于故障导致磁盘数据丢失,那么等同于整个HDFS文件系统数据丢失,如果NameNode块映射关系的内存爆满,那么等同于整个HDFS文件系统无法再继续存储,换句话说,NameNode内存决定了HDFS能够存储的块数量,根据经验值,每个文件、目录和数据块的存储信息大约占 150 字节。
NameNode高可用
为了保证读写数据一致性,HDFS集群设计为只能有一个状态为Active的NameNode,这样就导致NameNode存在单点故障,官方提供了两种方式来解决这个问题:
QJM(推荐):通过同步编辑事务日志的方式备份命名空间数据,同时需要DataNode向所有NameNode上报块列表信息。还可以配置ZKFC组件实现故障自动转移。
NFS:将需要持久化的数据写入本地磁盘的同时写入一个远程挂载的网络文件系统做为备份。
是通过增加一个备用NameNode节点,这个备用的节点平时不工作,处于备用Standby的状态,这样就同时运行两个状态的节点,这两个节点状态分别是:Active和Standby。
我们知道,NameNode主要保存文件系统目录树信息和块映射关系,为了保证备用节点能够随时顶替上去,所以Standby节点需要定时同步Active节点的事务日志来更新本地的文件系统目录树信息,同时DataNode需要配置所有NameNode的位置,并向所有状态的NameNode发送块列表信息和心跳。
注意,同步事务日志来更新目录树这个工作交给了一个叫JournalNode的独立守护进程来完成,简称为QJM,一个NameNode对应一个QJM进程,当Active节点执行任何命名空间文件目录树修改时,它会将修改记录持久化到大多数QJM中,Standby节点从QJM中监听并读取编辑事务日志内容,并将编辑日志应用到自己的命名空间。发生故障转移时,Standby节点将确保在将自身提升为Active状态之前,从QJM读取所有编辑内容。
注意,QJM只是实现了数据的备份,当Active节点发送故障时,需要手工提升Standby节点为Active节点。如果要实现NameNode故障自动转移,则需要配套ZKFC组件来实现,ZKFC也是独立运行的一个守护进程,基于zookeeper来实现选举和自动故障转移。
块副本(Replication)和放置策略
每一个文件可以配置副本数量,默认是3,副本的作用是防止因某个DataNode挂掉或磁盘损坏而导致数据丢失,除此之外块副本还可以提高块可读取的节点,提高mapreduce计算任务向数据移动的概率。
因为同一个DataNode放置相同的块数据是没有意义的,所以NameNode不允许DataNode具有同一块的多个副本,换句话说副本数量配置不能大于DataNode节点的数量。
每个文件可以在写入时指定这个文件块的副本数量,也可以在未来修改某个文件的块副本数量,文件块的副本数量配置作为块元数据的一部分保存在NameNode中。
由于NameNode可以获取每个DataNode所属的机架ID,并且块副本数量配置信息保存在NameNode中,所以块的副本放置策略是由NameNode决定好返回给客户端的,副本放置策略简单总结一句话为:三分之一的副本位于写入器所在的节点上,三分之二的副本位于写入器所在的同一个机架上,其余三分之一则平均分布在其余机架上。如果副本数大于3个,则随机确定其它的副本位置,一般副本数量配置为3个是比较理想的。
当修改某个文件的块副本数量时,NameNode将重新根据策略复制或减少块副本。当某个DataNode超过一定的时间(默认10分钟)没有上报心跳给NameNode,NameNode将认为该DataNode不可用,将不会分配块写入到这个DataNode中,原来分配在这个DataNode的块副本将会重新在其它可用的DataNode上复制。
HDFS联邦
虽然HDFS HA解决了“单点故障”问题,但是在系统扩展性、整体性能和隔离性方面仍然存在问题。
(1) 系统扩展性方面,元数据存储在NN内存中,受内存上限的制约。
(2) 整体性能方面,吞吐量受单个NN的影响。
(3) 隔离性方面,一个程序可能会影响其他运行的程序,如一个程序消耗过多资源导致其他程序无法顺利运行。HDFS HA本质上还是单名称节点。HDFS联邦可以解决以上三个方面问题。
在HDFS联邦中,设计了多个相互独立的NN,使得HDFS的命名服务能够水平扩展,这些NN分别进行各自命名空间和块的管理,不需要彼此协调。每个DN要向集群中所有的NN注册,并周期性的发送心跳信息和块信息,报告自己的状态。
HDFS联邦拥有多个独立的命名空间,其中,每一个命名空间管理属于自己的一组块,这些属于同一个命名空间的块组成一个“块池”。每个DN会为多个块池提供块的存储,块池中的各个块实际上是存储在不同DN中的。
磁盘平衡器
在HDFS中,DataNode 将数据块存储到本地文件系统目录中,具体的目录可以通过配置 hdfs-site.xml 里面的 dfs.datanode.data.dir 参数。在典型的安装配置中,一般都会配置多个目录,并且把这些目录分别配置到不同的设备上,比如分别配置到不同的HDD(HDD的全称是Hard Disk Drive)和SSD(全称Solid State Drives,就是我们熟悉的固态硬盘)上。
当我们往HDFS上写入新的数据块,DataNode 将会使用volume选择策略来为这个块选择存储的地方。目前Hadoop支持两种volume选择策略:round-robin 和 available space(详情参见:HDFS-1804),我们可以通过 dfs.datanode.fsdataset.volume.choosing.policy 参数来设置。
循环(round-robin)策略将新块均匀分布在可用磁盘上;而可用空间( available-space )策略优先将数据写入具有最大可用空间的磁盘(通过百分比计算的)。正如下图所示:
默认情况下,DataNode 是使用基于round-robin策略来写入新的数据块。然而在一个长时间运行的集群中,由于HDFS中的大规模文件删除或者通过往DataNode 中添加新的磁盘仍然会导致同一个DataNode中的不同磁盘存储的数据很不均衡。即使你使用的是基于可用空间的策略,卷(volume)不平衡仍可导致较低效率的磁盘I/O。比如所有新增的数据块都会往新增的磁盘上写,在此期间,其他的磁盘会处于空闲状态,这样新的磁盘将会是整个系统的瓶颈。
Diskbalancer是一个命令行工具,可以在datanode的所有磁盘上均匀分配数据。此工具与Balancer不同, 后者负责集群范围的数据平衡。由于多种原因,数据在节点上的磁盘之间可能存在不均匀的扩散。这可能是由于大量写入和删除或由于磁盘更换造成的。此工具针对给定的datanode运行,并将块从一个磁盘移动到另一个磁盘。
---------------------- 正文结束 ------------------------
Java软件编程之家
以上是关于HDFS架构和原理的主要内容,如果未能解决你的问题,请参考以下文章