我们打个比方来说,当我们有一个数据,有300G,但是我们每个电脑的硬盘存储最大只有256G,这个时候,单独的一台电脑是无法存储这个300G的文件的,那么我们要怎么存储这个文件呢?hadoop之父根据2013年谷歌发布的论文就开发出了这样一个文件系统。HDFS的核心思想就是我们可以将300G的文件,将它们切割,分别存放到不同的电脑硬盘上,在这些电脑中通过一个管理者,将300G的数据分别分配给仆从,让它们分别去存储。
提示:适用场景可以在看过hdfs系统架构后再回过来理解
适用的场景有:
一、HDFS适用于存储非常大的文件,对延时没有要求的;
二、HDFS采用了流式的数据访问,可以支持一次写入,多次读取。
三、商业硬件上,不需要特别贵的机器,可以节约成本
四、需要高容错性,这个意思就是说它能很好的进行数据的备份
五、为数据存储提供了很好的扩展性,也就是理论上可以存储无限大的数据,但是这个主要也是受制于管理者也就是hdfs系统中的namenode的存储大小。
不适用的场景有:
一、需要对数据处理在毫秒级别的,那么就不适用于hdfs,hdfs是为了高吞吐量而设计的。
二、大量小文件,由于管理者namenode是用来记录仆从节点的datanode的数据信息的,如果仆从节点文件小,就会造成浪费大量的namenode资源。打个比方,就是当你存储一个10G的文件,我namenode只需要些一个100k的文件来描述和记录怎么去查找,而你存储100M,我也需要同样的100k去记录,那么我是不是就比较浪费namenode的资源。当处理数十亿文件时,namnode也会有上限。
三、不支持多方写入
HDFS是一个主从结构
hdfs是由四部分组成:hdfs客户端(client)、namenode、datanode、secondarynamenode
hdfs客户端:
(1):文件切分。文件上传到hdfs系统时,由客户端将数据文件切割为一个一个的block,然后进行存储
(2):与namenode进行交互,获取文件位置信息
(3):与datanode进行交互,对数据进行读取或写入。
(4):客户端可以提供一些命令来管理和访问hdfs
namenode:它就是一个管理者,一个主管
(1)管理hdfs的名称空间
(2)管理数据块(block)的映射信息
(3)配置副本策略
(4)处理客户端读写请求
datanode:他就是一个仆从slave,执行namenode的命令
(1):执行存储block块
(2):执行数据块的读写操作
secondarynamenode:我们这里只要说到是第二,就不是高可用的场景,也就不是备胎,当namenode宕机时并不能替换去工作的
(1):辅助namenode,进行管理,分担其的工作量
(2):定期合并fsimage和edits,并推送给namenode
(3):在紧急情况备份恢复namenode的工作
namenode作用前面已经介绍了,还有一个重要的点就是我们存储文件的上限文件数还是受限于namenode的内存大小,我们继续对namenode的具体作用来进行了解。
(一)、namenode的元数据信息。存储在datanode的block块的文件名,文件目录,文件属性每个文件块的块列表。以及列表中的块与datanode中的块的地址映射关系在内存中加载文件系统中每个文件和每个数据块的引用关系,数据会定期保存到磁盘。
(二)、namenode文件操作。namenode负责元数据的操作datanode负责处理文件内容的读写请求。数据流不会经过namenode,但会询问它跟哪个datanode联系。
(三)、namenode副本。文件块存储在哪个datanode上是由namenode决来了定的,namenode根据全局情况做出放置副本的决定(读者可不必强行理解)
(四)、namenode心跳机制。全局管理数据块的复制,周期性的接受心跳机制和状态信息。如果发现没有心跳,就表明datanode宕机,就会准备把宕机的数据列表返回,并对数据块进行重新复制。
datanode的具体作用:
datanode是负责真实的数据存储服务
(一):datanode以数据块的形式存储数据
(二):datanode响应客户端的读写请求
(三):datanode周期性的向namenode反馈心跳,数据块状态信息,数据块的缓存信息。
HDFS的副本机制、
应用场景或作用如下:
1.一个文件有可能大于集群中的任何一个磁盘
2.使用块作为存储单位可以简化存储子系统
3.块非常适合数据备份,提高容错性
机架感知(这里有一个面试点,稍微了解一下)
hdfs有一个存放副本的策略:以默认副本数3为例
首先第一个副本块存放在本机,第二个副本块存放在跟本机在同一机架内的服务节点,第三个副本块存放在不同机架内的其它服务节点。
最重要的两个点,面试必了解的点!!!
(1):client客户端发起文件上传请求,通过rpc与namnode建立起通讯,namenode去检查是否存在,返回是否可以上传
(2):client请求第一个block块该传输到哪个datanode上
(3):namenode根据配置文件中备份数量及机架感知原理进行范培返回可用的datanode地址a、b、c
(4):client请求其中的一台a请求上传数据,rpc建立联系,a调用b,调用c,然后返回客户端
(5):client开始传block,以packet为单位(64k),然后a向bc,a每传一个会放入一个应答队列等待应答
(6):数据分割之后一个个传输,反方向向逐个发送ack正确应答,最终再由第一个a发送回ack返回给客户端,当第一个写入后就会进行第二,第三个的写入
(1):客户端向namenode发送rpc请求,来请求文件block的文件位置
(2):namenode会视情况返回文件列表,返回的datanode地址列表,会按照集群的拓扑结构得出datanode与客户端的距离,距离近的排在前面。
(3):client选取离得近的block的datanode来读取,如果本身就是datanode,那么直接从本地获取,(短路读取的特性)
(4):底层上时建立socket stream方法,重复调用父类的read方法。
(5):若读完block后,文件读取还没结束就像下一个datanode获取下一批block列表
(6):读取完一个datanode都会进行checksum验证,如果读取时出现错误,客户端会通知namenode,然后从下一个datanode中有该block副本中去读取。
(7):read方法是并行读取block信息,不是一块一块的读的,namenode只是返回请求包含块的datanode地址,而不是返回请求块的数据。
(8):最终读取的所有block会合并为一个完整的文件。