HDFS特点
HDFS(Hadoop Distributed File System,即Hadoop分布式文件系统)是hadoop生态系统的一个重要组成部分,是hadoop中的的存储组件,在整个Hadoop中的地位非同一般,是最基础的一部分,因为它涉及到数据存储,MapReduce等计算模型都要依赖于存储在HDFS中的数据。HDFS是一个分布式文件系统,以流式数据访问模式存储超大文件,将数据分块存储到一个商业硬件集群内的不同机器上。
超大文件。目前的hadoop集群能够存储PB级的数据。
流式数据访问。HDFS的访问模式是:一次写入,多次读取,更加关注的是读取整个数据集的整体时间。
商用硬件。HDFS集群的设备不需要多么昂贵和特殊,只要是一些日常使用的普通硬件即可。正因为如此,hdfs节点故障的可能性还是很高的,所以必须要有机制来处理这种单点故障,保证数据的可靠。
不支持低时间延迟的数据访问。hdfs关心的是高数据吞吐量,不适合那些要求低时间延迟数据访问的应用。
单用户写入,不支持任意修改。hdfs的数据以读为主,只支持单个写入者,并且写操作总是以添加的形式在文末追加,不支持在任意位置进行修改。
HDFS体系架构
HDFS 是一个主/从(Master/Slave)体系架构,由于分布式存储的性质,集群拥有两类节点 NameNode 和 DataNode。
NameNode(名称节点):系统中通常只有一个,中心服务器的角色,管理存储和检索多个 DataNode 的实际数据所需的所有元数据,响应客户请求。
DataNode(数据节点):系统中通常有多个,是文件系统中真正存储数据的地方,在NameNode 统一调度下进行数据块的创建、删除和复制。
NameNode
NameNode管理分布式文件系统的元数据,包括文件目录树、文件到数据块Block的映射关系等。这些数据保存在内存里,同时这些数据还以两个文件形式永久保存在本地磁盘上:命名空间镜像文件(fsimage)和编辑日志文件(editlog)。fsimage是内存命名空间元数据在外存的镜像文件,editlog文件则记录着用户对文件的各种操作记录,当客户端对hdfs中的文件进行新增或者修改操作,操作记录首先被记入editlog文件中,当客户端操作成功后,相应的元数据会更新到内存meta.data中,防止发生意外导致丢失内存中的数据。fsimage和editlog两个文件结合可以构造出完整的内存数据。
NameNdoe还负责对DataNode的状态监控。DataNode定期向NameNode发送心跳以及所存储的块的列表信息。NameNode可以知道每个DataNode上保存着哪些数据(Block信息),DataNode是否存活,并可以控制DataNode启动或是停止。若NameNode发现某个DataNode发生故障,会将其存储的数据在其他DataNode机器上增加相应的备份以维护数据副本(默认为3,可在配置文件中配置)保持不变。
如果NaneNode服务器失效,集群将失去所有的数据。因为我们将无从知道哪些DataNode存储着哪些数据。因此NameNode的高可用,容错机制很重要。
DataNode
DataNode负责数据的实际存储和读/写工作。HDFS会将文件切割成固定大小的数据块(Block),每个数据块又以多副本的形式存储在集群上,如果出现故障导致某一副本丢失,那么可以从其它副本恢复,默认保留3个副本。
NameNode通过心跳消息来确定DataNodes的有效性。对于超过时间未收到心跳消息的DataNode,系统认定这个DataNode已经失效,NameNode会马上将其上的数据备份到集群中其他机器上。当这个DataNode节点排除故障后,重新回到集群中,该节点上还保存着原来那批数据,在NameNode收到该节点的Block信息后,会命令某些DataNode删除掉多余的备份数据。
客户端上传文件过程
步骤详解:
1)客户端向NameNode请求上传文件
2)NameNode检查客户端要求上传的文件是否存在,目标目录是否存在
3)NameNode响应客户端是否可以上传文件
4)若第3步获得可以上传的信息,客户端向NameNode发出请求,询问第一块block该上传到哪里
5)NameNode查询DataNodes状态信息(忙碌情况,远近情况等)
6)NameNode返回3个DataNodes地址给客户端
7)客户端请求与最近的一个DataNode节点(假设为datanode1)建立传输通道,并告知其还要传给datanode2和datanode3。datanode1会请求与datanode2建立连接,datanode2会请求与datanode3建立连接。
8)datanode3响应datanode2的连接请求,通道建立成功。同理,datanode2响应datanode1,datanode1响应客户端。
9)客户端收到通道建立成功的消息后,开始向datanode1发送block1的数据,以一个个package(64k)为单位通过通道向datanode1写数据,datanode1收到数据会将其存在本地缓存中,一边向datanode2传数据,一边将缓存中的数据保存到磁盘上。
10)客户端在传送数据时会有一个package的应答队列,datanode1每收到一个package后就向客户端发回消息(datanode1不用等待datandoe2发回应答信息才给客户端发送信息,客户端只保证datanode1收到了数据就行,后面的事它交给了datanode1)
11)当一个block传输完成之后,客户端再次请求namenode上传第二个block
NameNode如何选择DataNode
客户端在上传数据时,请求NameNode告诉其应该往哪几个DataNode上传副本。NameNode需要综合考虑DataNode的可靠性,写入带宽,读出带宽等因素。默认情况下,在运行客户端的那个节点上存放第1个副本,如果客户端运行在集群之外,则随机选择一个节点存放第1块,但NameNode会尽量选择那些情况好的DataNode(存储不太满,当时不太忙,带宽比较高)。第2个副本存放在与第1个副本所在机架不同的另一个机架上的DataNode中(随机选择另一机架上的另一情况较好的DataNode),第3个副本存在与第2个副本相同机架但不同DataNode上。
所有有关块复制的决策统一由 NameNode 负责,NameNode 会周期性地接收集群中DataNode的心跳和块报告。一个心跳的到达表示这个数据节点是正常的。一个块报告包括该数据节点上所有块的列表。
客户端下载文件文件
步骤详解:
1)客户端跟NameNode通信,请求下载某个数据。
2)NameNode查询元数据信息以及Block位置信息。
3)将数据所在的DataNode信息返回给客户端。
4)客户端根据数据所在的DataNode,挑选一台距离自己最近的DataNode,并向其发出下载文件的请求(若所需数据不在一台DataNode上保存,则分别向多台DataNode发出请求)。
5)DataNode响应客户端请求,将数据返回给客户端。
6)从多个DataNode获得的数据不断在客户端追加,形成完整的数据
NameNode与Secondary NameNode
因为NameNode上保存着整个HDFS集群上的所有元数据信息,如果NameNode宕机,集群将失去所有数据,因此NameNode的容错机制十分重要,Hadoop为此提供了两种机制。
第一种是在配置文件里配置NameNode的工作目录为多个,这样可以将元数据信息存到多块磁盘上,或是多台机器上,甚至可以将元数据存在远程挂载的网络文件系统中(NFS),可以通过配置使NameNode在多个文件系统上实时保存元数据。这样一来,NameNode的工作目录所在的磁盘损坏后,还有其他磁盘上的数据可用。
第二种是运行一个辅助NameNode,被称为Secondary NameNode(第二名称节点)。Secondary NameNode的职责并不是作为NameNode的热备份机,其主要作用是定期从NameNode拉取fsimage和editlog,并将两者合并成新的fsimage,将新的fsimage返回给NameNode。这种方式,一方面可以避免NameNode上的编辑日志过大,另一方面将合并操作放在Secondary NameNode上可以节省NameNode的cpu时间和内存,减轻NameNode的工作压力,让NameNode更专注于自己的本职工作。Secondary NameNode中保存的fsimage数据总是会滞后于NameNode内存中的元数据,所以在NameNode宕机后,难免会有部分的数据丢失。
Secondary NameNode的工作
Secondary NameNode将NameNode上积累的所有editlog下载到本地,并加载到内存进行merge,这个过程称为checkpoint。
步骤详解:
1)Secondary NameNode通知NameNode要进行checkpoint了。(定时,或是NameNode上的editlog数量达到一定规模)。
2)NameNode做准备。
3)Secondary NameNode将NameNode的editlogs下载到本地磁盘上。
4)Secondary NameNode将editlogs和fsimage加载到内存中,进行合并产生新的fsimage。
5)Secondary NameNode将新的fsimage传回给NameNode(覆盖NameNode上旧的fsimage文件),并将其保存到本地磁盘上覆盖掉旧的fsimage。
NameNode高可用(High Availability,HA)
即使将NameNode内存中的元数据备份在多个文件系统中,并通过Secondary NameNode的checkpoint功能防止NameNode的数据丢失,但依然无法实现NameNode的高可用。NameNode一旦失效,整个系统将无法提供服务,管理员通过冷启动的方式让新的NameNode上线需要一段等待的时间(几十分钟,甚至更长)。新的NameNode在响应服务前必须经历以下以下步骤:将元数据导入内存;重做编辑日志文件;接收到足够多的来自DataNode的数据块报告并退出安全模式(数据块的位置信息不保存在元数据中,需要NameNode启动时在DataNode向其汇报的块信息中获取)。
针对以上问题,hadoop的2.x版本提出了NameNode的HA解决方案。
1)主控服务器由一主(Active NameNode,ANN)一从(Standby NameNode,SNN)两台服务器构成。
2)ANN响应客户端请求,SNN作为ANN的热备份机,同步ANN保存的元数据,在ANN失效时转换成新的ANN,快速提供服务。
3)ANN和SNN之间通过高可用的共享存储系统保持数据一致(ANN将数据写入共享存储系统,SNN一直监听共享系统,一旦数据发生改变就将其加载到自己内存中)
4)datanode同时向ANN和SNN汇报心跳和block信息。
5)故障转移控制器(Failover Contraller,FC),监控ANN和SNN的状态,并不断向ZK集群汇报心跳信息。
6)ZK集群"选举领导者",一旦发现ANN失效,就重新选举SNN作为新的领导者,FC通知其转变为新的ANN。Hadoop刚启动时,两台NameNode都是SNN,zk集群通过选举产生领导者作为ANN。
7)snn负责做checkpoint。
NameNode联盟(联邦HDFS)
1)namenode的内存数据包括两块内容,命名空间和数据块池(在namenode联盟中这两块数据相加被称为命名空间卷)。
2)命名空间中保存的内容包括文件或目录的拥有者,修改日期,以及文件被切分为哪几个块等信息,但不包括块到底是存储在哪些datanode中的信息(block位置信息)。
3)数据块池中保存着block位置信息(namenode刚启动时并没有block位置信息,是由datanode向其发送的block块信息中获取的)
4)datanode很好地支持水平扩展,但单一namenode受内存空间限制,使得HDFS中所能容纳的最大文件数量受到限制(一个大文件和一个小文件的元数据所占内存空间大小是基本相同,所以不适合存小文件,会很快占满namenode的内存)。
5)单一namanode使得所有来自客户端的请求都由一台服务器响应,很容易达到其性能上线,无法实现性能上的水平扩展。
6)单一namenode无法隔离来自不同客户的请求(比如本地实验时,对namenode的负载影响会导致正常用户的访问请求受到延迟等)
由于单一namenode存在以上4,5,6所述的问题,hadoop2.0给出了namenode联盟的解决方案,实现对namenode的水平扩展。
1)将一个大的命名空间切割成若干子命名空间,每个namenode管理命名空间中的一部分(如一个namenode管理/user下的所有文件,另一个管理/test下的所有文件)。
2)每个namenode单独管理自己的命名空间和数据块池(也可将所有数据块池抽离出来,由另外的服务器集群来担任此功能),两两之间不进行通信,一个namenode宕机不会影响其他namenode工作。
3)所有datanode被所有namenode共享,还是担任存储数据的功能。每个数据块的信息保存在唯一的某个数据块池中。
4)所有datanode都要注册每一个namenode,为每个namenode提供存储数据的服务。
5)每个datanode向所有的namenode发送心跳和block信息,每个namenode再根据自己的子命名空间维护自己的数据块池。