目录
NameNode和Secondary Namenode的具体分工
概念
hdfs是Hadoop分布式文件系统,用来存储超大文件。
以流式数据访问(一次写入,多次读取,所以读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。)
节点
namenode:
主节点,也是master,管理文件系统的命名空间。维护文件系统树以及整棵树内所有的文件和目录。(简单来说就是所有节点的位置,可用空间,以及所有数据块的位置信息,副本数量等等信息)
这些信息以两个文件的形式永久保存在本地磁盘,命名空间镜像文件fsimage和编辑日志文件editslog。
namenode也记录各个数据块所在的节点信息,但不永久保存这些位置信息,会在系统启动时,根据数据节点信息重建。(后面详细说明)
datanode:
从节点,用来存储文件块,接受namenode和client的调配,定期向namenode发送他们所存储的块列表。
Secondary Namenode:
协助namenode对数据的维护,若namenode发生宕机,协助对节点信息的重建,(后面也详细说明,原谅我太懒了。。。)
存储文件模式
分块:
hdfs把一个大文件划分成多个块大小的小文件,存储在不同的节点上,每个块的大小默认是128M。块设置较大的目的是,为了最小化寻址开销。
块也不适合过大,那样执行数据任务时间较长,处理速度变慢。
但是块设置过小,每个块的元数据也会占有一定的空间,会造成一定的资源浪费。
好处:
这种模式的好处就是,文件的大小可以大于任意一个磁盘的容量。
举个🌰,假设你有一个10T的文件,你的磁盘容量只有1T,但是你有十台机器,那么就可以把这个文件分成多份,放入多个节点。这样不仅解决超大文件的存储问题,读取的速度也会变快,从原来一次性要读10T大小文件的时间,到现在同时读取1T的时间,最后合并文件。
数据备份:
每个数据块都有备份,存储在不同节点上,防止某个节点宕机而造成文件的永久性损失。
若某个节点宕机,则会拿取副本数据,因为DataNode会定期向NameNode发送自己节点所存储的块信息,NameNode发现有节点出错,副本数不够,则会在新节点创建数据副本。
原来的DataNode节点修复重启启动后,原来存储的多余的块信息,NameNode感知后,也会进行删除,防止有垃圾数据的存在,占用空间。
占用空间:
hdfs中如果小于一个块大小的文件不会占据整个块的空间,例如如果有一个1M的文件存储在一个128M大小的块中,文件只使用1M的磁盘空间。
//以下命令可以列出各个文件由哪些块构成
% hdfs fsk /-files -blocks
优缺点
优点
- 数据安全,每个块都有数据备份,默认是3份,分布在不同节点上
- 对硬件要求不是很高,因为hdfs有很好的容错性
缺点
- 不适合用在低延迟的数据访问(因为hdfs适合用在大文件的存储,数据访问上会有一定的延时)
- 不适合大量小文件的存储(元数据会在namenode上占有空间)
- 不适合文件的修改,hdfs支持一次写入,多次读取;或者追加
- 不适合多用户同时写入
文件写入
客户端请求namenode上传数据,新建文件,namenode接收到请求后,检查当前文件是否存在以及客户端是否有新建文件的权限,若通过,则返回可用的datanode节点信息,否则抛异常。
由此,客户端可以开始写入数据:
注意:客户端是获取到DataNode节点信息后,由客户端向DataNode发送文件,而不是NameNode发送,NameNode只负责提供可用的节点信息。
写入数据时,会将它分成一个个的数据包放入内部队列。
DataStreamer处理数据队列,挑选出适合存储数据副本的一组datanode,并请求namenode分配数据块。
这组DataNode组成一个管线,数据以流式传输到管线中的第一台DataNode,然后由第一台发送给第二台,第二台发送给第三台以此类推。
收到所有DataNode的确认信息后,删除队列。
若任一DataNode在写入数据期间发生故障:
- 首先关闭管线,把队列中的所有数据包添加回队列的最前端。
- 为存储在另一正常的DataNode的当前数据块指定一个新的标识,将该标识传送给namenode。这样在故障DataNode恢复后,可以删除存储的部分数据块。
- 从管线中删除故障的DataNode,基于剩下的正常DataNode建立新管线
- 余下的数据块正常写入新管线
- 当NameNode注意到副本量不足时,会在另一个节点上创建新的副本。
文件读取
客户端请求NameNode获取到文件元数据信息,返回输入流(从磁盘输入到内存)
就近挑选一台DataNode,建立输入流(这个就近,大家可以去了解一下网络拓扑的概念,我也没有太深入研究,后续如果有了解,会写下来让大家参考,如果没有~那就是没有了~~~~)
DataNode向流中写入输入
关闭
到这里,hdfs文件的读取流程就完成了(写的不是特别详细,一些很细节的地方都一笔带过了,如果后面有精力,我会慢慢补充滴)
NameNode和Secondary Namenode的具体分工
namenode:
Namenode存放元数据在内存中,以树状的形式存储(方便对文件的增加删除修改)另外定期的把内存中的对象,序列化到磁盘中,变成一个镜像文件存储(fsimage)。
如果在还未序列化到磁盘中时,namenode挂机,为了防止内存中的数据丢失,在用户每做一个操作,引起元数据变化时,把这个操作记录到磁盘中edits文件。
记录操作相当于记录日志,追加比修改节省资源。
Edits定期滚动,和存储日志一样的机制,文件过大就进行切分。
NameNode每次启动时,会把镜像文件fsimage和日志文件edits进行合并,形成新的fsimage文件,然后再创建一个新的空edits。
但如果NameNode长时间不重启,edits就会很大,下次再重启,合并的速度就会非常慢,而为了防止这种情况发生,Secondary Namenode就出现了。
Secondary Namenode:
Secondnamenode定期的去把namenode上的fsimage文件下载过来,同时把edits也下载过来。接着把fsimage反序列化到磁盘和内存中去,变成元数据的目录数。
然后把这个文件上传到namenode上,并且有对应的编号。然后下一次再次合并就会取下一个fsimage文件和本地已有的fsimage文件进行合并,再次上传到namenode上。
namenode会保留最近的两个文件,把之前的文件删除。默认是每小时合并一次。
这样Secondnamenode就起到了辅助namonode的作用。
hdfs的数据完整性
hdfs如何保证数据的完整性,除了副本数和namenode的检测外,hdfs还会通过计算校验和的方式,保证数据的完整性。
Hadoop自带了一套原子操作,用于数据I/O操作
hdfs会对写入的所有数据,计算校验和,并且在读取数据的时候,验证校验和。
DataNode在收到数据后,在存储该数据和验证结果之前,就对数据进行验证。客户端把数据以及校验和发送到管线中,管线的最后一个DataNode负责验证校验和。如果检测错误,就抛异常
客户端从DataNode读取数据的时候,也会校验数据与DataNode中存储的校验和是否一致。
每个DataNode持久保存一个校验和日志,用于验证的校验和日志,记录每次最后验证时间。
校验和的计算代价很低,所以会通过额外的计算来保证数据的完整。
ps:这篇文章历时将近一个月才写完,经常写几个字就有事耽搁,所以写的比较潦草,若有不当,欢迎指出!