hdfs架构设计
HDFS主要由3个组件构成,分别是NameNode、SecondaryNameNode和DataNode,HSFS是以master/slave模式运行的,其中NameNode、SecondaryNameNode 运行在master节点,DataNode运行slave节点。
NameNode
当一个客户端请求一个文件或者存储一个文件时,它需要先知道具体到哪个DataNode上存取,获得这些信息后,客户端再直接和这个DataNode进行交互,而这些信息的维护者就是NameNode。
NameNode管理着文件系统命名空间,它维护这文件系统树及树中的所有文件和目录。NameNode也负责维护所有这些文件或目录的打开、关闭、移动、重命名等操作。对于实际文件数据的保存与操作,都是由DataNode负责。当一个客户端请求数据时,它仅仅是从NameNode中获取文件的元信息,而具体的数据传输不需要经过NameNode,是由客户端直接与相应的DataNode进行交互。元信息都存储在NameNode内存中,大量小文件会占用大量内存。
NameNode保存元信息的种类有:
- 文件名目录名及它们之间的层级关系
- 文件目录的所有者及其权限
- 每个文件块的名及文件有哪些块组成
需要注意的是,NameNode元信息并不包含每个块的位置信息,所以并不会持久化这些数据,这些信息会在NameNode启动时从各个DataNode获取并保存在内存中,因为这些信息会在系统启动时由数据节点重建。把块位置信息放在内存中,在读取数据时会减少查询时间,增加读取效率。NameNode也会实时通过心跳机制和DataNode进行交互,实时检查文件系统是否运行正常。
元信息的持久化
在NameNode中存放元信息的文件是 fsimage。在系统运行期间所有对元信息的操作都保存在内存中并被持久化到另一个文件edits中。并且edits文件和fsimage文件会被SecondaryNameNode周期性的合并。
SecondaryNameNode
需要注意,SecondaryNameNode并不是NameNode的备份。我们从前面的介绍已经知道,所有HDFS文件的元信息都保存在NameNode的内存中。在NameNode启动时,它首先会加载fsimage到内存中,在系统运行期间,所有对NameNode的操作也都保存在了内存中,同时为了防止数据丢失,这些操作又会不断被持久化到本地edits文件中。
Edits文件存在的目的是为了提高系统的操作效率,NameNode在更新内存中的元信息之前都会先将操作写入edits文件。在NameNode重启的过程中,edits会和fsimage合并到一起,但是合并的过程会影响到Hadoop重启的速度,SecondaryNameNode就是为了解决这个问题而诞生的。
SecondaryNameNode的角色就是定期的合并edits和fsimage文件,我们来看一下合并的步骤:
- 合并之前告知NameNode把所有的操作写到新的edites文件并将其命名为edits.new。
- SecondaryNameNode从NameNode请求fsimage和edits文件。
- SecondaryNameNode把fsimage和edits文件合并成新的fsimage文件。
- NameNode从SecondaryNameNode获取合并好的新的fsimage并将旧的替换掉,并把edits用第一步创建的edits.new文件替换掉。
- 更新fstime文件中的检查点。
最后再总结一下整个过程中涉及到NameNode中的相关文件
- fsimage :保存的是上个检查点的HDFS的元信息
- edits :保存的是从上个检查点开始发生的HDFS元信息状态改变信息
- fstime:保存了最后一个检查点的时间戳
DataNode
DataNode是hdfs中的worker节点,它负责存储数据块,Block 默认是64MB(HDFS2.0改成了128MB),也负责为系统客户端提供数据块的读写服务,同时还会根据NameNode的指示来进行创建、删除、和复制等操作。
当客户端上传一个大文件时,HDFS 会自动将其切割成固定大小的 Block,为了保证数据可用性,每个 Block 会以多备份的形式存储,默认是3份。
此外,它还会通过心跳定期向NameNode发送所存储文件块列表信息。当对hdfs文件系统进行读写时,NameNode告知客户端每个数据驻留在哪个DataNode,客户端直接与DataNode进行通信,DataNode还会与其它DataNode通信,复制这些块以实现冗余。
文件读取过程
1、跟namenode通信查询元数据(block所在的datanode节点),找到文件块所在的datanode服务器
2、挑选一台datanode(就近原则,然后随机)服务器,请求建立socket流
3、datanode开始发送数据(从磁盘里面读取数据放入流,以packet为单位来做校验)
4、客户端以packet为单位接收,先在本地缓存,然后写入目标文件,后面的block块就相当于是append到前面的block块最后合成最终需要的文件。
文件写入过程
1、跟namenode通信请求上传文件,namenode检查目标文件是否已存在,父目录是否存在
2、namenode返回是否可以上传
3、client会先对文件进行切分,比如一个block块128m,文件有300m就会被切分成3个块,一个128M、一个128M、一个44M请求第一个 block该传输到哪些datanode服务器上
4、namenode返回datanode的服务器
5、client请求一台datanode上传数据(本质上是一个RPC调用,建立pipeline),第一个datanode收到请求会继续调用第二个datanode,然后第二个调用第三个datanode,将整个pipeline建立完成,逐级返回客户端
6、client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(一个packet为64kb),当然在写入的时候datanode会进行数据校验,第一台datanode收到一个packet就会传给第二台,第二台传给第三台;
7、当一个block传输完成之后,client再次请求namenode上传第二个block的服务器。
备份放置
Hadoop的默认策略是将第一个副本放在与客户端相同的节点上(对于在群集外部运行的客户端,随机选择一个节点,尽管系统尝试不选择太满或太忙的节点)。第二个副本放置在与第一个(机架外)不同的机架上,随机选择。第三个副本与第二个副本放在同一个机架上,但是在随机选择的不同节点上。
考虑两点:
- 数据安全:在某个节点发生故障时,不会丢失数据备份;
- 网络传输开销:在备份数据同步过程中,尽量减少网络传输中的带宽开销;