HDFS设计初探

 本文整理自网上多篇文章。

    1、HDFS基本概念

    (1)数据块(block)

    * HDFS(Hadoop Distributed File System)默认的最基本的存储单位是64M的数据块。
    *  和普通文件系统相同的是,HDFS中的文件是被分成64M一块的数据块存储的。
    *  不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。
    (2)元数据节点(Namenode)和数据节点(datanode)

    * 元数据节点用来管理文件系统的命名空间
         * 其将所有的文件和文件夹的元数据保存在一个文件系统树中。
         * 这些信息也会在硬盘上保存成以下文件:命名空间镜像(namespace image)及修改日志(edit log)
         * 其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而这些信息并不存储在硬盘上,而是在系统启动的时候从数据节点收集而成的。
    * 数据节点是文件系统中真正存储数据的地方。
        * 客户端(client)或者元数据信息(namenode)可以向数据节点请求写入或者读出数据块。
        * 其周期性的向元数据节点回报其存储的数据块信息。
    * 从元数据节点(secondary namenode)

        * 从元数据节点并不是元数据节点出现问题时候的备用节点,它和元数据节点负责不同的事情。

        * 其主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。这点在下面会相信叙述。
        * 合并过后的命名空间镜像文件也在从元数据节点保存了一份,以防元数据节点失败的时候,可以恢复。

    1)元数据节点文件夹结构

    https://i-blog.csdnimg.cn/blog_migrate/7b03810210d093ce83882a47ccdcf0a3.png

    * VERSION文件是java properties文件,保存了HDFS的版本号。
        * layoutVersion是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
        * namespaceID是文件系统的唯一标识符,是在文件系统初次格式化时生成的。
        * cTime此处为0
        * storageType表示此文件夹中保存的是元数据节点的数据结构。

[plain]  view plain copy
  1. namespaceID=1232737062  
  2. cTime=0  
  3. storageType=NAME_NODE  
  4. layoutVersion=-18  
     2)文件系统命名空间映像文件及修改日志
    * 当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit log)
    * 元数据节点在内存中保存了文件系统的元数据信息。在记录了修改日志后,元数据节点则修改内存中的数据结构。
    * 每次的写操作成功之前,修改日志都会同步(sync)到文件系统。
    * fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在硬盘上直接修改。
    * 同数据的机制相似,当元数据节点失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,然后逐一重新执行修改日志中的操作。
    * 从元数据节点就是用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上的
    * checkpoint的过程如下:
        * 从元数据节点通知元数据节点生成新的日志文件,以后的日志都写到新的日志文件中。
        * 从元数据节点用http get从元数据节点获得fsimage文件及旧的日志文件。
        * 从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。
        * 从元数据节点奖新的fsimage文件用http post传回元数据节点
        * 元数据节点可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),然后更新fstime文件,写入此次checkpoint的时间。
        * 这样元数据节点中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变的很大了。

hadoop01

图1.1 checkpoint的过程

    3)从元数据节点的目录结构

image

    4)数据节点的目录结构


image   

    * 数据节点的VERSION文件格式如下:

[plain]  view plain copy
  1. namespaceID=1232737062  
  2. storageID=DS-1640411682-127.0.1.1-50010-1254997319480  
  3. cTime=0  
  4. storageType=DATA_NODE  
  5. layoutVersion=-18  
    * blk_<id>保存的是HDFS的数据块,其中保存了具体的二进制数据。

    * blk_<id>.meta保存的是数据块的属性信息:版本信息,类型信息,和checksum
    * 当一个目录中的数据块到达一定数量的时候,则创建子文件夹来保存数据块及数据块属性信息。
    2、数据流(data flow)

    (1)读文件的过程
    * 客户端(client)用FileSystem的open()函数打开文件
    * DistributedFileSystem用RPC调用元数据节点,得到文件的数据块信息。
    * 对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。
    * DistributedFileSystem返回FSDataInputStream给客户端,用来读取数据。
    * 客户端调用stream的read()函数开始读取数据。
    * DFSInputStream连接保存此文件第一个数据块的最近的数据节点。
    * Data从数据节点读到客户端(client)
    * 当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
    * 当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
    * 在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
    * 失败的数据节点将被记录,以后不再连接。

image

图2.1 读文件的过程

    (2)写文件的过程

    * 客户端调用create()来创建文件
    * DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件。
    * 元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
    * DistributedFileSystem返回DFSOutputStream,客户端用于写数据。
    * 客户端开始写入数据,DFSOutputStream将数据分成块,写入data queue。
    * Data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。
    * Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
    * DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
    * 如果数据节点在写入的过程中失败:
        * 关闭pipeline,将ack queue中的数据块放入data queue的开始。
        * 当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。
        * 失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。
        * 元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。
        * 当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。

image

图2.2 写文件的过程

    3、Hadoop的文件系统接口

   Hadoop整合了众多文件系统,在其中有一个综合性的文件系统抽象,它提供了文件系统实现的各类接口,HDFS只是这个抽象文件系统的一个实例。提供了一个高层的文件系统抽象类org.apache.hadoop.fs.FileSystem,这个抽象类展示了一个分布式文件系统,并有几个具体实现,如下表1-1所示。

文件系统

URI方案

Java实现

org.apache.hadoop

定义

Local

file

fs.LocalFileSystem

支持有客户端校验和本地文件系统。带有校验和的本地系统文件在fs.RawLocalFileSystem中实现。

HDFS

hdfs

hdfs.DistributionFileSystem

Hadoop的分布式文件系统。

HFTP

hftp

hdfs.HftpFileSystem

支持通过HTTP方式以只读的方式访问HDFSdistcp经常用在不同HDFS集群间复制数据。

HSFTP

hsftp

hdfs.HsftpFileSystem

支持通过HTTPS方式以只读的方式访问HDFS

HAR

har

fs.HarFileSystem

构建在Hadoop文件系统之上,对文件进行归档。Hadoop归档文件主要用来减少NameNode内存使用

KFS

kfs

fs.kfs.KosmosFileSystem

Cloudstore(其前身是Kosmos文件系统)文件系统是类似于HDFSGoogleGFS文件系统,使用C++编写。

FTP

ftp

fs.ftp.FtpFileSystem

FTP服务器支持的文件系统。

S3(本地)

s3n

fs.s3native.NativeS3FileSystem

基于Amazon S3的文件系统。

S3(基于块)

s3 

fs.s3.NativeS3FileSystem

基于Amazon S3的文件系统,以块格式存储解决了S35GB文件大小的限制。

表1-1 Hadoop的文件系统

    Hadoop提供了许多文件系统的接口,用户可以使用URI方案选取合适的文件系统来实现交互。

    4、Hadoop I/O系统

    要理解Hadoop的MapReduce编程,首先必须了解下Hadoop的I/O知识,要不一看到IntWritable、LongWritable、Text、NullWritable等概念就有点犯晕,看到和普通的Java程序类似的MapReduce程序就觉得很难。如果这时候你知道其实IntWritable就是其他语言如Java、C++里的int类型,LongWritable就是其他语言里的long,Text类似String,NullWritable就是Null,这样你就会很轻易的明白Hadoop的MapReduce程序。就像在学习其他编程语言之前必须先学习数据类型一样,在学习Hadoop的MapReduce编程之前,最好先学习下Hadoop的I/O知识。这里就简要介绍Hadoop的I/O知识。
    (1)序列化和反序列化
    序列化(Serialization)就是结构化的对象转化为字节流,这样可以方便在网络上传输和写入磁盘进行永久存储(原因看完这部分后就明白了)。反序列化(deserialization)就是指将字节流转回结构化对象的逆过程。
    序列化和反序列化在分布式数据处理里主要出现在进程间通行和永久存储两个应用领域。在Hadoop 系统中,系统中多个节点上的进程间通信是通过远程过程调用(romote procedure call,R PC)实现的,RPC协议将消息序列转化为二进制流后发送到远程节点,远程节点接着将二进制流反序列化为消息,所以RPC对于序列化有以下要求(也就是进程间通信对于序列化的要求):
    1)紧凑,紧凑的格式可以提高传输效率,充分利用网络带宽,要知道网络带宽是数据中心的一种非常重要的资源。
    2)快速,进程间通信是分布是系统的重要内容,所以必须减少序列化和反序列化的开销,这样可以提高整个分布式系统的性能。
  3)可扩展,通信协议为了满足一些新的需求,比如在方法调用的过程中增加新的参数,或者新的服务器系统要能够接受老客户端的旧的格式的消息,这样就需要直接引进新的协议,序列化必须满足可扩展的要求。
    4)互操作,可以支持不同语言写的客户端(比如C++、java、Python等等)与服务器交互。
    前面说了序列化的目的是可以方便在网络上传输和写入磁盘进行永久存储,前面讲了进程间通信对于序列化的要求,下面来说一说数据永久存储对于序列化的要求。前面说的4个序列化的要求也是数据永久存储所要求的,存贮格式紧凑可以高效的利用存储空间,快速可以减少读写数据的额外开销,可扩张这样就可以方便的读取老格式的数据,互操作就可以满足不同的编程序言来读写永久存贮的数据。
    (2)Hadoop的序列化格式——Writabale
    前面介绍了序列化对于分布式系统是至关重要的,Hadoop 定义了自己的序列化格式Writable,它是通过Java语言实现的,格式紧凑速度快。Writable是Hadoop的核心,很多MapReduce程序都会为键和值使用它。
     1)Writabale接口
    Writable接口定义了两个方法,一个将其状态写到DataOutput二进制流(往二进制流里面写数据),一个从DataInput二进制流读取其状态(从二进制流里读取数据)。
     2)Writable类
     Hadoop自带的org.apache.hadoop.io包含有广泛的Writable类可供选择。下面给出Writable类的层次结构。 

Hadoop I/O系统介绍

图3.1 Writable类的层次结构

    下面介绍几个常用的Writable类:
    1)Text类
   Text类是针对UTF-8序列(UTF-8是UNICODE的一种变长字节字符编码,又称万国码)的Writable类,一般认为他等价与java.lang.String的Writable类。但是他和String还是有一些差异的。Text的索引是按编码后字节序列中的位置来实现的,String是按其所包含的char编码单元来索引的。看下面的例子: 

[java]  view plain copy
  1. String s=String("\u0041\u00df\uu6671\ud801\uDc00");  
  2. Text t=Text("\u0041\u00df\uu6671\ud801\uDc00");  
  3. s.indexof("\u0041")==0            t.find("\u0041")==0  
  4. s.indexof("\u00df")==1            t.find("\u00df")==1  
  5. s.indexof("\u6671")==2            t.find("\u6671")==3  
  6. s.indexof("\ud801\uDc00")==3      t.find(\ud801\uDc00")==6  
  7. s.length()==5                     s.getBytes("UTF-8").length()==10  
  8. t.getLength()==10(1+2+3+4)   
  通过字节偏移量来进行位置索引,实现对Text类的Unicode字符迭代是非常复杂的,因为不能简单的通过增加位置的索引值来实现。所以必先将Text对象转化为java.nio.BytesBuffer对象,然后利用缓冲区对Text对象反复调用bytesToCodePoint()静态方法,该方法能获取下一代码的位置。
由于Text类不像java.lang.String类那样有丰富的字符串操作API,所以在一些情况下为了方便处理,需要将Text类转化为String类,这一过程通过toString来实现。
     2)ByteWritable类,二进制数据数组的封装,它的序列化格式为一个用于指定后面数据字节数的整数域(4字节),后跟字节本身。
     3)NullWritabe,是Writable的一个特殊类型,它的序列化长度为0,类似于null。
     4)ObjectWritable类,是对java基本类型(String,enum,Writable,null或这些类型组成的数组)的一个通用封装。
     5)Writable集合类,共有4个集合类,其中ArrayWritable是对Writable的数组的实现,TwoDArrayWritable是对Writable的二维数组的实现,MapWritable是对Map的实现,SortedMapWritable是对SortedMap的实现。
    6)定制的Writable类,我们可以根据自己的需求构造自己的Writable类,可以根据需要控制二进制表示和排序顺序,由于Writable是MapReduce数据路径的核心,所以调整二进制表示能对性能残生显著效果。
      (3)Hadoop的序列化框架——Avro
    Avro(读音类似于[ævrə])是Hadoop的一个子项目,由Hadoop的创始人Doug Cutting(也是Lucene,Nutch等项目的创始人,膜拜)牵头开发,当前最新版本1.3.3。Avro是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据;动态语言友好,Avro提供的机制使动态语言可以方便地处理Avro数据。
    当前市场上有很多类似的序列化系统,如Google的Protocol Buffers, Facebook的Thrift。这些系统反响良好,完全可以满足普通应用的需求。针对重复开发的疑惑,Doug Cutting撰文解释道:Hadoop现存的RPC系统遇到一些问题,如性能瓶颈(当前采用IPC系统,它使用Java自带的DataOutputStream和DataInputStream);需要服务器端和客户端必须运行相同版本的Hadoop;只能使用Java开发等。但现存的这些序列化系统自身也有毛病,以Protocol Buffers为例,它需要用户先定义数据结构,然后根据这个数据结构生成代码,再组装数据。如果需要操作多个数据源的数据集,那么需要定义多套数据结构并重复执行多次上面的流程,这样就不能对任意数据集做统一处理。其次,对于Hadoop中Hive和Pig这样的脚本系统来说,使用代码生成是不合理的。并且Protocol Buffers在序列化时考虑到数据定义与数据可能不完全匹配,在数据中添加注解,这会让数据变得庞大并拖慢处理速度。其它序列化系统有如Protocol Buffers类似的问题。所以为了Hadoop的前途考虑,Doug Cutting主导开发一套全新的序列化系统,这就是Avro,于09年加入Hadoop项目族中。
 Avro是Hadoop中的一个重要的项目,不是三言两语能说清楚的,这篇文章是专门介绍Avro的,感觉写的不错,地址: http://langyu.iteye.com/blog/708568
     (4)SequenceFile和MapFile
    Hadoop的HDFS和MapReduce子框架主要是针对大数据文件来设计的,在小文件的处理上不但效率低下,而且十分消耗内存资源(每一个小文件占用一个Block,每一个block的元数据都存储在namenode的内存里)。解决办法通常是选择一个容器,将这些小文件组织起来统一存储。HDFS提供了两种类型的容器,分别是SequenceFile和MapFile。
这一篇博文是专门介绍SequenceFile和MapFile的,写的不错,想详细理解的可以查看,文章地址: http://blog.youkuaiyun.com/javaman_chen/article/details/7241087
     关于Hadoop I/O还有数据的完整性和数据压缩的知识,由于篇幅原因,这里不再一一介绍。 
     5、HDFS优缺点及改进策略

    优点:

    (1)处理超大文件。这里的超大文件通常是指百MB、设置数百TB大小的文件。目前在实际应用中,HDFS已经能用来存储管理PB级的数据了。
    (2)流式的访问数据。HDFS的设计建立在更多地响应"一次写入、多次读取"任务的基础上。这意味着一个数据集一旦由数据源生成,就会被复制分发到不同的存储节点中,然后响应各种各样的数据分析任务请求。在多数情况下,分析任务都会涉及数据集中的大部分数据,也就是说,对HDFS来说,请求读取整个数据集要比读取一条记录更加高效。
   (3)运行于廉价的商用机器集群上。Hadoop设计对硬件需求比较低,只须运行在低廉的商用硬件集群上,而无需昂贵的高可用性机器上。廉价的商用机也就意味着大型集群中出现节点故障情况的概率非常高。这就要求设计HDFS时要充分考虑数据的可靠性,安全性及高可用性。

    缺点:

    (1)不适合低延迟数据访问
    HDFS不太适合于那些要求低延时(数十毫秒)访问的应用程序,因为HDFS是设计用于大吞吐量数据的,这是以一定延时为代价的。HDFS是单Master的,所有的对文件的请求都要经过它,当请求多时,肯定会有延时。

  改进策略:对于那些有低延时要求的应用程序,HBase是一个更好的选择。现在HBase的版本是0.20,相对于以前的版本,在性能上有了很大的提升,它的口号就是goes real time。使用缓存或多master设计可以降低client的数据请求压力,以减少延时。还有就是对HDFS系统内部的修改,这就得权衡大吞吐量与低延时了,HDFS不是万能的银弹。
    (2)无法高效存储大量小文件
    因为Namenode把文件系统的元数据放置在内存中,所以文件系统所能容纳的文件数目是由Namenode的内存大小来决定。一般来说,每一个文件、 文件夹和Block需要占据150字节左右的空间,所以,如果你有100万个文件,每一个占据一个Block,你就至少需要300MB内存。当前来说,数 百万的文件还是可行的,当扩展到数十亿时,对于当前的硬件水平来说就没法实现了。还有一个问题就 是,因为Map task的数量是由splits来决定的,所以用MR处理大量的小文件时,就会产生过多的Map task,线程管理开销将会增加作业时间。举个例子,处理10000M的文件,若每个split为1M,那就会有10000个Map tasks,会有很大的线程开销;若每个split为100M,则只有100个Map tasks,每个Map task将会有更多的事情做,而线程的管理开销也将减小很多。
    要想让HDFS能处理好小文件,有不少方法:
  1)利用SequenceFile, MapFile, Har等方式归档小文件,这个方法的原理就是把小文件归档起来管理,HBase就是基于此的。对于这种方法,如果想找回原来的小文件内容,那就必须得知道与归档文件的映射关系。
    2)横向扩展,一个Hadoop集群能管理的小文件有限,那就把几个Hadoop集群拖在一个虚拟服务器后面,形成一个大的Hadoop集群。google也是这么干过的。

    3)多Master设计,这个作用显而易见了。正在研发中的GFS II也要改为分布式多Master设计,还支持Master的Failover,而且Block大小改为1M,有意要调优处理小文件啊。附带个Alibaba DFS的设计,也是多Master设计,它把Metadata的映射存储和管理分开了,由多个Metadata存储节点和一个查询Master节点组成。Alibaba DFS目前下载不了,加群60534259吧(Hadoop技术交流),群共享里有下 。
    (3)不支持多用户写和任意修改文件
    目前Hadoop只支持单用户写,不支持并发多用户写。可以使用Append操作在文件的末尾添加数据,但不支持在文件的任意位置进行修改。这些特性可能会在将来的版本中加入,但是这些特性的加入将会降低Hadoop的效率,就拿GFS来说吧,这篇文章里就说了google自己的人都用着Multiple Writers很不爽。
    利用Chubby、ZooKeeper之类的分布式协调服务来解决一致性问题。

    6、从HDFS看分布式文件系统的设计需求

  分布式文件系统的设计目标大概是这么几个:透明性、并发控制、可伸缩性、容错以及安全需求等。我想试试从这几个角度去观察HDFS的设计和实现,可以更清楚地看出HDFS的应用场景和设计理念。
     (1)透明性

    如果按照开放分布式处理的标准确定就有8种透明性:访问的透明性、位置的透明性、并发透明性、复制透明性、故障透明性、移动透明性、性能透明性和伸缩透明性。对于分布式文件系统,最重要的是希望能达到5个透明性要求:
    1)访问的透明性:用户能通过相同的操作来访问本地文件和远程文件资源。HDFS可以做到这一点,如果HDFS设置成本地文件系统,而非分布式,那么读写 分布式HDFS的程序可以不用修改地读写本地文件,要做修改的是配置文件。可见,HDFS提供的访问的透明性是不完全的,毕竟它构建于java之上,不能 像NFS或者AFS那样去修改unix内核,同时将本地文件和远程文件以一致的方式处理。
  2)位置的透明性:使用单一的文件命名空间,在不改变路径名的前提下,文件或者文件集合可以被重定位。HDFS集群只有一个Namenode来负责文件系统命名空间的管理,文件的block可以重新分布复制,block可以增加或者减少副本,副本可以跨机架存储,而这一切对客户端都是透明的。
    3)移动的透明性,这一点与位置的透明性类似,HDFS中的文件经常由于节点的失效、增加或者replication因子的改变或者重新均衡等进行着复制或者移动,而客户端和客户端程序并不需要改变什么,Namenode的edits日志文件记录着这些变更。
    4)性能的透明性和伸缩的透明性:HDFS的目标就是构建在大规模廉价机器上的分布式文件系统集群,可伸缩性毋庸置疑,至于性能可以参考它首页上的一些benchmark。
    (2)并发控制

    客户端对于文件的读写不应该影响其他客户端对同一个文件的读写。要想实现近似原生文件系统的单个文件拷贝语义,分布式文件系统需要做出复 杂的交互,例如采用时间戳,或者类似回调承诺(类似服务器到客户端的RPC回调,在文件更新的时候;回调有两种状态:有效或者取消。客户端通过检查回调承 诺的状态,来判断服务器上的文件是否被更新过)。HDFS并没有这样做,它的机制非常简单,任何时间都只允许一个写的客户端,文件经创建并写入之后不再改 变,它的模型是 write-one-read-many , 一次写,多次读。这与它的应用场合是一致,HDFS的文件大小通常是兆至T级的,这些数据不会经常修改,最经常的是被顺序读并处理,随机读很少,因此 HDFS非常适合MapReduce框架或者web crawler应用。HDFS文件的大小也决定了它的客户端不能像某些分布式文件系统那样缓存常用到的几百个文件。

    (3)文件复制功能

    一个文件可以表示为其内容在不同位置的多个拷贝。这样做带来了两个好处:访问同个文件时可以从多个服务器中获取从而改善服务的伸缩 性,另外就是提高了容错能力,某个副本损坏了,仍然可以从其他服务器节点获取该文件。HDFS文件的block为了容错都将被备份,根据配置的 replication因子来,默认是3。副本的存放策略也是很有讲究,一个放在本地机架的节点,一个放在同一机架的另一节点,另一个放在其他机架上。这 样可以最大限度地防止因故障导致的副本的丢失。不仅如此,HDFS读文件的时候也将优先选择从同一机架乃至同一数据中心的节点上读取block。
    (4)硬件和操作系统的异构性

    由于构建在java平台上,HDFS的跨平台能力毋庸置疑,得益于java平台已经封装好的文件IO系统,HDFS可以在不同的操作系统和计算机上实现同样的客户端和服务端程序。
     (5)容错能力

    在分布式文件系统中,尽量保证文件服务在客户端或者服务端出现问题的时候能正常使用是非常重要的。HDFS的容错能力大概可以分为两个方面:文件系统的容错性以及Hadoop本身的容错能力。文件系统的容错性通过这么几个手段:
    1)在Namenode和Datanode之间维持心跳检测
,当由于网络故障之类的原因,导致Datanode发出的心跳包没有被Namenode正常收 到的时候,Namenode就不会将任何新的IO操作派发给那个Datanode,该Datanode上的数据被认为是无效的,因此Namenode会检 测是否有文件block的副本数目小于设置值,如果小于就自动开始复制新的副本并分发到其他Datanode节点。
    2)检测文件block的完整性,HDFS会记录每个新创建的文件的所有block的校验和。当以后检索这些文件的时候,从某个节点获取block,会首先确认校验和是否一致,如果不一致,会从其他Datanode节点上获取该block的副本。
    3)集群的负载均衡,由于节点的失效或者增加,可能导致数据分布的不均匀,当某个Datanode节点的空闲空间大于一个临界值的时候,HDFS会自动从其他Datanode迁移数据过来。
  4)Namenode上的fsimage和edits日志文件是HDFS的核心数据结构,如果这些文件损坏了,HDFS将失效。因而,Namenode可以配置成支持维护多个FsImage和Editlog的拷贝。任何对FsImage或者Editlog的修改,都将同步到它们的副本上。它总是选取最近的一致的FsImage和Editlog使用。Namenode在 HDFS是单点存在,如果Namenode所在的机器错误,手工的干预是必须的。
      5)文件的删除,删除并不是马上从Namenode移出namespace,而是放在/ trash目录随时可恢复,直到超过设置时间才被正式移除。
     再说Hadoop本身的容错性,Hadoop支持升级和回滚,当升级Hadoop软件时出现bug或者不兼容现象,可以通过回滚恢复到老的Hadoop版本。
     最后一个就是安全性问题,HDFS的安全性是比较弱的,只有简单的与unix文件系统类似的文件许可控制,未来版本会实现类似NFS的kerberos验证系统。
    总结下:HDFS作为通用的分布式文件系统并不适合,它在并发控制、缓存一致性以及小文件读写的效率上是比较弱的。但是它有自己明确的设计目标,那就是支 持大的数据文件(兆至T级),并且这些文件以顺序读为主,以文件读的高吞吐量为目标,并且与MapReduce框架紧密结合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值