HDFS是主从结构。一个HDFS集群由一个NameNode和一组DataNode组成。NameNode是主服务器,负责管理文件系统命名空间以及客户端对文件的访问。DataNode通常每个节点一个,负责管理存储。HDFS对外暴露了一个文件系统命名空间并允许用户数据作为文件存储。在内部实现上,一个文件会被分割成一个或多个block,这些block存储在一组DataNode上。NameNode负责执行文件系统命名空间操作,例如打开,关闭,重命名文件和目录等。此外NameNode还维护着block和DataNode之间的映射关系。DataNode负责处理来自客户端的读写请求,并根据NameNode的指令创建,删除,备份block。
NameNode和DataNode都是运行在通用机器上的软件。这些机器通常使用Linux系统。HDFS使用Java构建,任何支持Java的机器都可以运行NameNode和DataNode。一种典型的集群部署方式是使用一台机器运行NameNode,其它机器每台运行一个DataNode实例。
HDFS使用传统的分层文件结构。用户可以创建目录并在目录下存储文件。文件系统命名空间结构与传统文件系统类似,用户可以创建,删除文件,将文件从一个目录移动到另一个目录,重命名文件。HDFS支持用户限额和访问权限。
NameNode维护整个文件系统命名空间,它会记录任何对命名空间的修改。应用程序可以指定HDFS中文件的备份数量。文件的拷贝数称为该文件的备份因子。这个信息也存储在NameNode中。
HDFS可以跨机器存储海量文件。每个文件分成一个block的序列存储。为了容错,文件的block会被备份。每个文件的block大小和备份因子都是可配置的。
文件中所有block的大小是相等的(除了最后一个),而对append和hsync提供可变长block支持后,用户可以直接创建一个新block,不必继续填充最后一个block。
应用程序可以指定文件的备份数。备份因子可在文件创建时指定,也可以稍后修改。HDFS的文件都是一次写入的(除了append和truncate),并且任何时候都只有一个写入器。
NameNode决定如何备份block。它周期性的接收来自DataNode的心跳检测和block报表。收到心跳检测说明DataNode工作正常,block报表包含该DataNode上的所有block。
备份文件的位置对HDFS的可用性和性能至关重要。对备份的优化让HDFS从众多分布式系统中脱颖而出。这个工作需要大量的优化和经验。机架感知备份放置策略的目的是提高数据的可靠性,可用性和网络带宽利用率。目前的备份放置策略实现是这个方向上的第一步。短期目标是在生产环境上对其进行验证,更多的了解它的行为,为测试和研究更复杂的策略奠定基础。
大型HDFS集群的机器通常隶属于多个机架。两个不同机架上的节点进行通信必须通过交换机。一般来说,同一机架机器之间的网络带宽要优于不同机架机器间的网络带宽。
NameNode通过Hadoop Rack Awareness进程确定每个DataNode所属的机架ID。一个简单但是并非最优的策略是将备份放置在独立的机架上。这种策略可以避免机架故障时丢失数据,读数据时也可以利用多个机架的网络带宽。这种策略在集群中平均分配备份文件,这样组件发生故障时可以平衡负载。但是这种策略会增加写入成本,因为数据需要跨机架传输。
最常见的情况,备份因子是3。HDFS的放置策略是:如果写入器位于DataNode上,则将副本放置在本地计算机,否则随机选择一个DataNode,另一个副本放置在另一个远程机架的节点上,最后一个副本放在同一个远程机架的另一个节点上。这种策略减少了机架间的写入流量,从而提高写性能。机架发生故障的几率远小于节点故障几率。这种策略并不影响数据可靠性和可用性,但是它确实减少了读操作时的聚合网络带宽,因为一个block被放置到两个机架上而不是三个。这种策略的文件副本并不是均匀的分布在所有机架上,副本的三分之一位于一个节点,剩下的三分之二位于另一个机架上。这种策略可以提高写性能,而不会影响数据可靠性和读性能。
如果备份因子大于3,那么第四个和之后的副本随机放置,同时要保证副本数量不能超过机架的上限(公式: (replicas - 1) / racks + 2 )。
由于DataNode不能放置同一个block的多个副本,所以最大备份因子就是最大DataNode数。
在提供了存储类型和存储策略的支持之后,除了机架感知,NameNode放置副本时也会考虑放置策略。NameNode首先根据机架感知选择节点,然后根据备份文件的放置策略检查该节点的存储类型,如果该候选节点没有要求的存储类型,NameNode会查找下一个节点。如果第一轮没有找到足够的节点放置备份,NameNode会使用后备存储类型开始第二轮查找。
目前,副本放置策略依然在开发中。
为了减少带宽消耗和读延迟,HDFS会尝试找寻一个离读请求最近的副本。如果读请求节点所在机架有这样一个副本,HDFS就优先使用这个副本。如果HDFS集群跨越多个数据中心,则本地数据中心的副本优先于远程副本。
启动HDFS时,NameNode会进入一种称为安全模式的特殊状态。安全模式下数据block无法备份。NameNode会从DataNode接收心跳检测和block报表。block报表包含该DataNode下所有数据block的列表信息。每个block都有一个指定的最小备份数。只有block的最小备份数登记到NameNode中后,block才可以备份。备份登记结束后,NameNode退出安全模式。这是如果还有block不满足最小备份数的条件,NameNode才开始备份这些block。
HDFS命名空间由NameNode保存,NameNode使用一个称为EditLog的事务日志记录对文件系统元数据的所有更改。例如,创建一个新文件会在EditLog中插入一条对应记录,同样的,修改文件备份因子也会插入一条记录。NameNode使用本地文件存储EditLog。整个文件系统命名空间,包括文件与block之间的映射关系,文件系统数据等,都保存在FsImage文件中。
NameNode在内存中维护文件系统命名空间和文件block映射关系的镜像。当NameNode启动,或者某个阈值触发了检查点时,NameNode从磁盘上读取FsImage和EditLog的内容,将所有EditLog中的事务操作应用到FsImage的内存镜像中,然后在磁盘上生成一个全新的FsImage。之后可以截断EditLog,因为所有事务都已持久化到FsImage。这个过程称为检查点。检查点的目的是通过获取文件系统元数据的快照并保存到FsImage来保证HDFS文件系统元数据的一致性。读取FsImage可能很快,但是持续编辑FsImage就不同了。因此我们将操作记录到EditLog中,而不是直接修改FsImage。在检查点期间,所有EditLog操作应用到FsImage。检查点可以按周期触发( dfs.namenode.checkpoint.period ),也可以按事务数触发( dfs.namenode.checkpoint.txns )。如果两个属性都设置了,第一个满足的阈值会触发检查点。
DataNode在本地文件系统中存储HDFS数据。DataNode对HDFS文件一无所知,它以block为单位存储HDFS数据。DataNode不会在同一个目录下保存所有文件。相反,它使用启发式方法来确定每个目录的最佳文件数,并适时创建子目录。在同一个目录下创建所有文件并不是最佳选择,因为本地文件系统可能无法支持一个目录下的大量文件。DataNode启动时,它会扫描整个本地文件系统,生成一个本地文件与数据block之间的关系列表,将其发送给NameNode,这个列表称为block报告。
所有HDFS通信协议都构建在TCP/IP协议之上。客户端通过TCP端口与NameNode建立连接,它使用ClientProtocol与NameNode交互。DataNode使用DataProtocol与NameNode交互。一个RPC抽象封装了客户端协议和DataNode协议。NameNode从不初始化任何RPC,它只是响应来自的客户端和DataNode的请求。
HDFS的主要目标是即使出现故障也可以可靠的存储数据。三种常见的故障分别是:NameNode故障,DataNode故障和网络分区。
DataNode周期性的发送心跳检测给NameNode。网络分区可能导致某些DataNode无法连接NameNode。NameNode无法收到DataNode的心跳检测后,它会把这样的DataNode标记为dead,并不在发送新的I/O请求。注册到死亡DataNode上的数据对HDFS来说不再可用,也会导致某些block的备份数少于文件指定的最小备份数。NameNode持续追踪block的备份情况并在必要时初始化备份操作。重备份的原因是多种多样的:DataNode不可用,某个备份文件损坏,DataNode磁盘故障,或者文件的备份因子增大。
为了避免DataNode状态抖动引起的备份风暴,标记DataNode死亡的超时时间设置的很长(默认超过10分钟)。用户可以设置一个更短的时间将DataNode标记为陈旧(stale),这样可以避免对性能敏感的工作负载的陈旧DataNode的读写操作。
HDFS架构与数据重平衡scheme兼容。scheme可以在DataNode的磁盘空间低于某个阈值时将数据移动到另一个DataNode上。如果对某个文件的需求特别高,scheme还可以动态创建额外的副本并平衡到整个集群中。这些数据平衡scheme还未实现。
从DataNode中读取的block可能是损坏的。损坏的原因有多种:磁盘故障,网络故障,或者软件问题。HDFS客户端会对文件内容进行校验和检查。当客户端创建一个HDFS文件时,它会计算出文件所有block的校验和并保存在同一个命名空间的一个独立的隐藏文件中。当客户单检索文件时还要检查对应校验和文件中的值。如果校验和不匹配,客户端会尝试该block其它节点上的副本。
FsImage和EditLog是HDFS的核心数据结构。如果它们发生损坏,HDFS就无法使用了。因此,可以通过配置让NameNode维护多个FsImage和EditLog的拷贝。对两个文件的修改会同步到所有拷贝中。这种同步操作会降低NameNode的TPS,但是这种牺牲是可接受的,因为HDFS是数据密集,不是元数据密集。NameNode重启时,它会选择最一致的FsImage和EditLog使用。
另一种减低故障的办法是使用HA。
(略)
HDFS的目的是支持大型文件。HDFS支持一次写入多次读取。一个典型的block大小是128MB。因此,HDFS文件按照128MB的大小分割,每个block可能分布在不同的节点上。
客户端向HDFS文件写入数据时,如果备份因子是三,NameNode使用备份目标选择算法检索出一组DataNode。这个列表是可以存储副本的DataNode。客户端先向第一个DataNode写入数据,DataNode接收数据并将数据传输到列表中的第二个DataNode。第二个DataNode开始接收数据并继续传输数据到第三个DataNode。这样,数据通过管道从一个DataNode传输到下一个。
(略)
如果开启了trash配置,从FS shell中删除的文件并不会立刻从HDFS中删除,HDFS将它移动到一个trash目录(每个用户都有自己的trash目录, /user/<username>/.Trash )。只要文件还在trash目录中就可以快速恢复。
最近删除的文件移动到 /user/<username>/.Trash/Current 目录中,每隔一段时间,HDFS会为这些文件创建检查点文件( /user/<username>/.Trash/<date>)并删除旧检查点文件。
如果trash中的文件过期了,NameNode将这些文件从命名空间中删除。与文件关联的block被释放。删除文件和空间释放之间可能会有延迟。
下面是一个例子,首先创建两个文件:
然后删除test1,该文件会被移到Trash目录:
接着跳过Trash删除test2:
现在可以查看Trash目录:
文件的备份因子降低后,NameNode选择可以删除的副本,在下次心跳检测时把信息发送给DataNode,之后DataNode删除block并释放空间。
用途:将单机的工作任务进行分拆,变成协同工作的集群。用以解决日益增加的文件存储量和数据量瓶颈。
通俗应用解释:
比如计算一个100M的文本文件中的单词的个数,这个文本文件有若干行,每行有若干个单词,每行的单词与单词之间都是以空格键分开的。对于处理这种100M量级数据的计算任务,把这个100M的文件拷贝到自己的电脑上,然后写个计算程序就能完成计算。
关键技术:
HDFS(Hadoop Distributed File System):
既可以是Hadoop 集群的一部分,也可以是一个独立的分布式文件系统,是开源免费的大数据处理文件存储系统。
HDFS是Master和Slave的主从结构(是一种概念模型,将设备分为主设备和从设备,主设备负责分配工作并整合结果,或作为指令的来源;从设备负责完成工作,一般只能和主设备通信)。主要由Name-Node、Secondary NameNode、DataNode构成。
Name-Node:分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等
Secondary NameNode:辅助 NameNode,分担其工作,紧急情况可以辅助恢复
DataNode:Slave节点,实际存储数据、执行数据块的读写并汇报存储信息给NameNode
HDFS客户端的存储流程:当客户需要写数据时,先在NameNode 上创建文件结构并确定数据块副本将要写道哪几个 datanode ,然后将多个代写 DataNode 组成一个写数据管道,保证写入过程完整统一写入。
读取数据时则先通过 NameNode 找到存储数据块副本的所有 DataNode ,根据与读取客户端距离排序数据块,然后取最近的。
大数据中最宝贵、最难以代替的就是数据,一切都围绕数据。
HDFS是最早的大数据存储系统,存储着宝贵的数据资产,各种新算法、框架要想得到广泛使用,必须支持HDFS,才能获取已存储在里面的数据。所以大数据技术越发展,新技术越多,HDFS得到的支持越多,越离不开HDFS。 HDFS也许不是最好的大数据存储技术,但依然是最重要的大数据存储技术 。
HDFS是如何实现大数据高速、可靠的存储和访问的呢?
Hadoop分布式文件系统HDFS的设计目标是管理数以千计的服务器、数以万计的磁盘,将大规模的服务器计算资源当作一个单一存储系统进行管理,对应用程序提供数以PB计的存储容量,让应用程序像使用普通文件系统一样存储大规模的文件数据。
文件以多副本的方式进行存储:
缺点:
优点:
HDFS的大容量存储和高速访问的实现。
RAID将数据分片后,在多块磁盘上并发进行读写访问,提高了存储容量、加快了访问速度,并通过数据冗余校验提高了数据可靠性,即使某块磁盘损坏也不会丢数据。将RAID的设计理念扩大到整个分布式服务器集群,就产生了分布式文件系统,这便是Hadoop分布式文件系统的核心原理。
和RAID在多个磁盘上进行文件存储及并行读写的思路一样,HDFS是在一个大规模分布式服务器集群上,对数据分片后进行并行读写及冗余存储。因为HDFS可部署在一个大的服务器集群,集群中所有服务器的磁盘都可供HDFS使用,所以整个HDFS的存储空间可以达到PB级。
HDFS是主从架构。一个HDFS集群会有一个NameNode(命名节点,简称NN),作为主服务器(master server)。
HDFS公开了文件系统名称空间,允许用户将数据存储在文件中,就好比我们平时使用os中的文件系统一样,用户无需关心底层是如何存储数据的。 在底层,一个文件会被分成一或多个数据块,这些数据库块会被存储在一组数据节点中。在CDH中数据块的默认128M。 在NameNode,可执行文件系统的命名空间操作,如打开,关闭,重命名文件等。这也决定了数据块到数据节点的映射。
HDFS被设计为可运行在普通的廉价机器上,而这些机器通常运行着一个Linux操作系统。一个典型的HDFS集群部署会有一个专门的机器只能运行 NameNode ,而其他集群中的机器各自运行一个 DataNode 实例。虽然一台机器上也可以运行多个节点,但不推荐。
负责文件数据的存储和读写操作,HDFS将文件数据分割成若干数据块(Block),每个DataNode存储一部分Block,这样文件就分布存储在整个HDFS服务器集群中。
应用程序客户端(Client)可并行访问这些Block,从而使得HDFS可以在服务器集群规模上实现数据并行访问,极大提高访问速度。
HDFS集群的DataNode服务器会有很多台,一般在几百台到几千台,每台服务器配有数块磁盘,整个集群的存储容量大概在几PB~数百PB。
负责整个分布式文件系统的元数据(MetaData)管理,即文件路径名、数据块的ID以及存储位置等信息,类似os中的文件分配表(FAT)。
HDFS为保证数据高可用,会将一个Block复制为多份(默认3份),并将多份相同的Block存储在不同服务器,甚至不同机架。当有磁盘损坏或某个DataNode服务器宕机,甚至某个交换机宕机,导致其存储的数据块不能访问时,客户端会查找其备份Block访问。
HDFS中,一个文件会被拆分为一个或多个数据块。默认每个数据块有三个副本,每个副本都存放在不同机器,而且每一个副本都有自己唯一的编号:
文件/users/sameerp/data/part-0的复制备份数设为2,存储的BlockID分别为1、3:
上述任一台服务器宕机后,每个数据块都至少还有一个备份存在,不会影响对文件/users/sameerp/data/part-0的访问。
和RAID一样,数据分成若干Block后,存储到不同服务器,实现数据大容量存储,并且不同分片的数据能并行进行读/写操作,实现数据的高速访问。
副本存放:NameNode节点选择一个DataNode节点去存储block副本的过程,该过程的策略是在可靠性和读写带宽间权衡。
《Hadoop权威指南》中的默认方式:
Google大数据“三驾马车”的第一驾是GFS(Google 文件系统),而Hadoop的第一个产品是HDFS,分布式文件存储是分布式计算的基础。
这些年来,各种计算框架、各种算法、各种应用场景不断推陈出新,但大数据存储的王者依然是HDFS。
磁盘介质在存储过程中受环境或者老化影响,其存储的数据可能会出现错乱。
HDFS对存储在DataNode上的数据块,计算并存储校验和(CheckSum)。在读数据时,重新计算读取出来的数据的校验和,校验不正确就抛异常,应用程序捕获异常后就到其他DataNode上读取备份数据。
DataNode监测到本机的某块磁盘损坏,就将该块磁盘上存储的所有BlockID报告给NameNode,NameNode检查这些数据块还在哪些DataNode上有备份,通知相应的DataNode服务器将对应的数据块复制到其他服务器上,以保证数据块的备份数满足要求。
DataNode会通过心跳和NameNode保持通信,如果DataNode超时未发送心跳,NameNode就会认为这个DataNode已经宕机失效,立即查找这个DataNode上存储的数据块有哪些,以及这些数据块还存储在哪些服务器上,随后通知这些服务器再复制一份数据块到其他服务器上,保证HDFS存储的数据块备份数符合用户设置的数目,即使再出现服务器宕机,也不会丢失数据。
NameNode是整个HDFS的核心,记录着HDFS文件分配表信息,所有的文件路径和数据块存储信息都保存在NameNode,如果NameNode故障,整个HDFS系统集群都无法使用;如果NameNode上记录的数据丢失,整个集群所有DataNode存储的数据也就没用了。
所以,NameNode高可用容错能力非常重要。NameNode采用主从热备的方式提供高可用服务:
集群部署两台NameNode服务器:
两台服务器通过Zk选举,主要是通过争夺znode锁资源,决定谁是主服务器。而DataNode则会向两个NameNode同时发送心跳数据,但是只有主NameNode才能向DataNode返回控制信息。
正常运行期,主从NameNode之间通过一个共享存储系统shared edits来同步文件系统的元数据信息。当主NameNode服务器宕机,从NameNode会通过ZooKeeper升级成为主服务器,并保证HDFS集群的元数据信息,也就是文件分配表信息完整一致。
软件系统,性能差点,用户也许可接受;使用体验差,也许也能忍受。但若可用性差,经常出故障不可用,就麻烦了;如果出现重要数据丢失,那开发摊上大事。
而分布式系统可能出故障地方又非常多,内存、CPU、主板、磁盘会损坏,服务器会宕机,网络会中断,机房会停电,所有这些都可能会引起软件系统的不可用,甚至数据永久丢失。
所以在设计分布式系统的时候,软件工程师一定要绷紧可用性这根弦,思考在各种可能的故障情况下,如何保证整个软件系统依然是可用的。
## 6 保证系统可用性的策略
任何程序、任何数据,都至少要有一个备份,也就是说程序至少要部署到两台服务器,数据至少要备份到另一台服务器上。此外,稍有规模的互联网企业都会建设多个数据中心,数据中心之间互相进行备份,用户请求可能会被分发到任何一个数据中心,即所谓的异地多活,在遭遇地域性的重大故障和自然灾害的时候,依然保证应用的高可用。
当要访问的程序或者数据无法访问时,需要将访问请求转移到备份的程序或者数据所在的服务器上,这也就是 失效转移 。失效转移你应该注意的是失效的鉴定,像NameNode这样主从服务器管理同一份数据的场景,如果从服务器错误地以为主服务器宕机而接管集群管理,会出现主从服务器一起对DataNode发送指令,进而导致集群混乱,也就是所谓的“脑裂”。这也是这类场景选举主服务器时,引入ZooKeeper的原因。ZooKeeper的工作原理,我将会在后面专门分析。
当大量的用户请求或者数据处理请求到达的时候,由于计算资源有限,可能无法处理如此大量的请求,进而导致资源耗尽,系统崩溃。这种情况下,可以拒绝部分请求,即进行 限流 ;也可以关闭部分功能,降低资源消耗,即进行 降级 。限流是互联网应用的常备功能,因为超出负载能力的访问流量在何时会突然到来,你根本无法预料,所以必须提前做好准备,当遇到突发高峰流量时,就可以立即启动限流。而降级通常是为可预知的场景准备的,比如电商的“双十一”促销,为了保障促销活动期间应用的核心功能能够正常运行,比如下单功能,可以对系统进行降级处理,关闭部分非重要功能,比如商品评价功能。
HDFS是如何通过大规模分布式服务器集群实现数据的大容量、高速、可靠存储、访问的。
1.文件数据以数据块的方式进行切分,数据块可以存储在集群任意DataNode服务器上,所以HDFS存储的文件可以非常大,一个文件理论上可以占据整个HDFS服务器集群上的所有磁盘,实现了大容量存储。
2.HDFS一般的访问模式是通过MapReduce程序在计算时读取,MapReduce对输入数据进行分片读取,通常一个分片就是一个数据块,每个数据块分配一个计算进程,这样就可以同时启动很多进程对一个HDFS文件的多个数据块进行并发访问,从而实现数据的高速访问。关于MapReduce的具体处理过程,我们会在专栏后面详细讨论。
3.DataNode存储的数据块会进行复制,使每个数据块在集群里有多个备份,保证了数据的可靠性,并通过一系列的故障容错手段实现HDFS系统中主要组件的高可用,进而保证数据和整个系统的高可用。
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)