HDFS详解

作者: Bloo_m | 来源:发表于2016-11-26 16:17 被阅读777次

    认识HDFS

    HDFS的特点:

    高容错性
    高吞吐量
    故障的检测和自动快速恢复
    流式的数据访问
    大数据集
    一次写入,多次读写

    HDFS不适用的场景

    不支持大量小文件的存储
    不适合随机读写
    不适合随意修改

    HDFS的组成

    hdfs是一个主从结构的体系,一个HDFS的集群由以下部分组成:
    NameNode(名字节点):一个用来管理文件的名字空间和调节客户端访问文件的主服务器
    DataNode(数据节点):一个或多个,用来管理存储

    HDFS的数据复制

    HDFS能可靠的在大量集群中存储非常大量的文件,它以块序列的形式存储每一个文件,文件中除了最后一个块的其他块都是相同的大小.属于文件的块为了故障容错而被复制.块的大小和复制数可以为每个文件配置.HDFS中的文件都是严格地要求任何时候只有一个写操作.

    名字节点(NameNode)来做所有的块复制,它周期性地接收来自集群中数据节点(DataNode)的心跳和块报告.一个心跳的收条表示这个数据节点是健康的,是渴望服务数据的.一个块报告包括该数据节点上的所有块列表.复制块放置位置的选择严重影响HDFS的可靠性和性能,因此机架的复制布局目的就是提高数据的可靠性、可用性和网络带宽的利用率

    默认复制数为3的情况下,HDFS放置方式是将第一个放在本地节点,将第二个复制放到本地机架上的另一个节点上,而将第三个复制到不同机架上的节点。这种方式减少了机架内的写流量,提高了写的性能.机架的失效机会远小于机器失效的机会

    在复制数为3的情况下,是备份在不同的机架上,而不是三个机架.文件的复制不是均匀地分布在机架上.1/3在同一个节点上,第二个1/3复制在同一个机架上,另外1/3是均匀地分布在其他机架上.

    可在hdfs-site.xml中修改dfs.replication的个数即修改复制个数,这种方案参数其实只在文件被写入dfs时起作用,虽然更改了配置文件,但是不会改变之前写入的文件的备份数,而且需要重启HDFS系统才能生效

    hadoop fs -setrep -R 1 /:这种方式可以改变整个HDFS里面的备份数,不需要重启HDFS系统

    数据块的复制是以pipeline的方式进行的

    HDFS复制的选择

    HDFS尝试满足一个读操作来自离它最近的复制。如果在读节点的同一个机架上有这个复制,则直接读.如果HDFS集群是跨越多个数据的中心,那么本地数据中心的复制优先于远程的复制

    HDFS的安全模式

    在启动的时候,NameNode会进入一个特殊的状态叫做安全模式。
    安全模式是不发生文件块的复制的
    NameNode接受DataNode的心跳和数据块报告,一个块报告包括数据节点向名字节点报告数据块的列表
    每一个块有一个特定的最小复制数,当NameNode检查这个块已经大于最小的复制数,就被认为是安全的复制了.当达到配置的块安全复制比例时,NameNode就退出安全模式.它将检测数据块的列表,将小于特定的复制数的块复制到其他的数据节点

    HDFS的元数据持久化

    HDFS的名字空间是由NameNode来存储的。
    NameNode用事务日志(EditsLog)来持久化每一个对文件系统的元数据的改变,即对元数据的每一步操作都会被记录到EditsLog中.NameNode在本地文件系统中用一个文件来存储这个EditsLog
    完整的文件系统名字空间、文件块的映射和文件系统的配置都存在一个叫Fsimage的文件中,Fsimage也是在NameNode的本地文件系统中
    CheckPoint(检查点):当NameNode启动的时候,它会从磁盘中读取Fsimage和EditsLog文件,然后将新的元数据刷新到本地磁盘中,生成一个新的Fsimage文件,至此EditsLog文件已经被处理并持久化的Fsimage中
    任何对Fsimage和EditsLog的更新都会同步地更新每一个副本

    HDFS架构

    HDFS架构是一个典型的主从架构,包括一个NameNode(主节点)和多个DataNode(从节点)
    架构图如下图所示:

    Paste_Image.png

    NameNode是整个文件系统的管理节点,它负责文件系统名字空间(NameSpace)的管理与维护,同时负责客户端文件操作的控制以及具体存储任务的管理与分配
    DataNode提供了真实文件数据的存储服务

    数据块

    Hadoop1.X默认的数据块大小是64MB
    Hadoop2.X默认的数据块大小是128MB
    HDFS上的文件系统也被划分为块大小的多个分块(Chunk)作为独立的存储单元.但与其他文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间

    为什么HDFS默认的Block为128MB(64MB)?

    HDFS的块之所以这么大,主要是为了把寻道(Seek)时间最小化.如果一个块足够大,从硬盘传输数据的时间将远远大于寻找块的起始位置的时间,这样就使HDFS的数据传输速度和硬盘的传输速度更加接近.

    分布式文件系统中的块进行抽象带来的好处:

    一个文件系统的大小可以大于网络中任意一个磁盘的容量
    使用块抽象而非整个文件作为存储单元,大大简化了存储子系统的设计.

    NameNode

    NameNode是管理者,一个Hadoop集群有一个NameNode节点,是一个通常在HDFS实例中的单独机器上运行的软件.它负责管理文件系统名字空间和控制外部客户机的访问

    NameNode决定是否将文件映射到DataNode的复制块上.
    实际的I/O事务并没有经过NameNode,只有表示DataNode和块的文件映射的元数据经过NameNode。当外部客户机发送请求要求创建文件时,NameNode会以块标识和该块的第一个副本的DataNode IP地址作为响应.这个NameNode还会通知其他将要接收该块的副本的DataNode

    NameNode主要功能如下:

    1:NameNode提供名称查询服务,它是一个Jetty服务器
    2:NameNode保存metadata信息.具体包括:文件owership和permissons;文件包含哪些块,Block保存在哪个DataNode(由DataNode启动时上报)
    3:NameNode的metadata信息在启动后会加载在内存

    DataNode

    Hadoop集群中包含一个NameNode和大量的DataNode,DataNode通常以机架的形式组织,机架通过一个交换机将所有系统连接起来

    DataNode响应来自HDFS客户机的读写请求,它们还响应来自NameNode的创建、删除和复制块的命令

    DataNode的功能如下:
    1:保存Block,每一个块对应一个元数据信息文件。这个文件主要描述这个块属于哪个文件,第几个块等信息
    2:启动DataNode线程的时候会向NameNode汇报Block信息
    3:通过向NameNode发送心跳保持其联系(3秒一次),如果NameNode10分钟没有收到DataNode的心跳,则认为其已经lost,并将其上的Block复制到其他DataNode

    SecondaryNameNode

    SecondaryNameNode(辅助元数据节点),会周期性地将EditsLog文件中记录对HDFS的操作合并到一个Fsimage中文件中,然后清空EditsLog文件.NameNode的重启会加载最新的一个Fsimage文件,并重新创建一个EditsLog文件来记录HDFS操作,由于EditsLog中记录的是从上一次Fsimage以后到现在的操作列表,所以会比较小

    如果没有SecondaryNameNode这个周期性的合并过程,当每次重启NameNode的时候,就会花费很长的时间,而这样周期性地合并就能减少重启的时间,同时也能保证HDFS系统的完整性

    Paste_Image.png

    SecondaryNameNode合并Fsimage和EditsLog文件过程如下:

    1:文件系统客户端进行写操作时,首先会把它记录在EditsLog中
    2:NameNode在内存中保存了文件系统的元数据信息.在记录修改日志后,NameNode修改内存中的数据结构
    3:每次的写操作成功之前,修改日志都会同步(Sync)到文件系统中
    4:Fsimage文件即名字空间映像文件,是内存中的元数据在硬盘上的CheckPoint,它是一种序列化的格式,并不能够在硬盘上直接修改
    5:当NameNode失败时,最新CheckPoint的元数据信息从Fsimage加载到内存中,然后逐一重新执行修改日志后的操作
    6:SecondaryNameNode就是用来帮助NameNode将内存中的元数据信息CheckPoint到硬盘上的.

    CheckPoint过程如下:

    1:SecondaryNameNode通知NameNode生成新的EditsLog,以后的日志都写到新的日志文件中
    2:SecondaryNameNode用Http Get从NameNode获得Fsimage文件以及旧的日志文件
    3:SecondaryNameNode将Fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的Fsimage文件
    4:SecondaryNameNode将新的Fsimage文件用Http Post传回NameNode
    5:NameNode可以将旧的Fsimage以及旧的EditLog,换成新的Fsimage文件和新的EditLog(第一步生成的),然后更新fstime文件,写入此次CheckPoint的时间
    6:这样NameNode中的Fsimage文件保存了最新的CheckPoint的元数据信息,日志文件也重新开始,不会变得很大了.

    SecondaryNameNode会周期性地将EditsLog文件进行合并,合并前提条件如下:

    EditsLog文件到达某一阀值时对其进行合并(默认为64MB,当文件大小超过64MB,就会触发EditsLog与Fsimage文件的合并,修改core-site.xml配置文件中的fs.checkpoint.period选项)

    每隔一段时间对其合并(默认为1小时合并一次,修改core-site.xml配置文件中的fs.checkpoint.size)

    机架感知

    默认情况下,Hadoop的机架感知是没有启用的.所以,通常情况下,Hadoop集群的HDFS在选择机器的时候是随机选择的.

    启用Hadoop机架感知功能,配置非常简单,在NameNode所在机器 的hadoop-site.xml文件中配置一个选项
    <property>
    <name>topology.script.file.name</name>
    <value>/path/to/script</value>
    </property>

    HDFS的RPC机制

    一般我们所了解的RPC(Remote Procedure Call,远程过程调用)机制都要面对两个问题:
    1对象调用方式;
    2序列/反序列化机制
    但Hadoop实现了自己简单的RPC组件,依赖Hadoop Writable类型的支持
    Hadoop Writable接口要求每个实现类都要确保将本类的对象正确序列化(writeObject)与反序列化(readObject)。因此,Hadoop RPC使用java动态代理与反射实现对象调用方式

    Paste_Image.png

    RPC的实现流程

    简单的说,Hadoop RPC = 动态代理+定制的二进制流

    实现流程如下:
    远程的对象拥有固定的接口,这个接口用户也是可见的,只是真正的实现(Object)只在服务端.用户如果想使用哪个实现,调用过程是:
    先根据那个接口动态代理生成一个代理对象,调用这个代理对象的时候,用户的调用请求被RPC捕捉到,然后包装成调用请求,序列化成数据流发送到服务端;服务端从数据流中解析出调用请求,然后根据用户所希望调用的接口,调用真正的实现对象,再把调用结果返回给客户端

    RPC的实体模型

    注意:用户在调用代理对象时RPC是怎样拦截这次调用请求的?

    创建代理对象时需要为它关联一个InvocationHandler,对代理对象的每次调用都会进入绑定的InvocationHandler中,RPC就从这里获取用户的请求

    Listener:监听RPC Server的端口,如果客户端有连接请求到达,它就接收连接,然后把连接转发到某个Reader,让Reader读取那个连接的数据。如果有多个Reader,当有新连接过来时,就在这些Reader间顺序分发。注意Hadoop0.21版本在支持多Reader时有个bug(JIRA),如果有Reader在Server运行期间没有被使用,Server进程不能正常关闭

    Reader:从某个客户端连接中读取数据流,把它转化成调用对象(Call),然后放到调用队列(call queue)里

    Handler:真正做事的实体,它从调用队列中获取调用信息,然后反射调用真正的对象,得到结果,再把此次调用放到响应队列(response queue)里

    >Responder:不断地检查响应队列中是否有调用信息,如果有,就把调用的结果返回给客户端
    
    Paste_Image.png

    HDFS的文件读取

    Paste_Image.png

    文件读取的流程如下:

        1:使用HDFS提供的客户度开发库Client,向远程的NameNode发起RPC请求
        2:NameNode会根据情况返回文件的部分或者全部Block列表,对于每个Block,NameNode都会返回有该Block副本的DataNode地址
        3:客户端开发库Client会选取离客户端最接近的DataNode来读取Block,如果客户端本身就是DataNode,将从本地直接获取数据
        4:读取完当前Block的数据后,关闭与当前的DataNode连接,并为读取下一个Block寻找最佳的DataNode
        5:读取完列表的Block后,且文件读取还没有结束,客户端开发库会继续向NameNode获取下一批Block列表
        6:读取完一个Block都会进行CheckSum验证,如果读取DataNode时会出现错误,客户端会通知NameNode,然后从下一个拥有该Block复制的DataNode继续读
    

    HDFS的文件写入

    Paste_Image.png

    写入文件的过程比读取复杂,步骤如下:

      1:使用HDFS提供的客户端开发库Client,向远程的NameNode发起RPC请求
      2:NameNode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功后会为文件创建一个记录,否则会让客户端抛出异常
      3:当客户端开始写入文件的时候,开发库会将文件切分多个packet,并在内部以数据队列(data queue)的形式管理这些packet,并向NameNode申请新的Block,获取用来存储replicas的合适的DataNode列表,列表的大小根据在NameNode中对replication的设置而定
      4:开始以管道(pipeline)的形式将Packet写入所有的replicas中。开发库把packet以流的方式写入第一个DataNode,该DataNode把packet存储之后,再把器传递给在此管道中的下一个DataNode,直到最后一个DataNode,这种写数据的方式呈流水线的形式
      5:最后一个DataNode成功存储之后会返回一个ack packet,在管道里传递给客户端,在客户端的开发库内部维护着ack queue,成功收到DataNode返回的ack packet后会从ack queue移除相应的packet
      6: 如果传输过程中,有某个DataNode出现了故障,当前的管道会被关闭,出现故障的DataNode会从当前的管道中移除,剩余的Block会继续剩下的DataNode中继续以管道的形式传输,同时NameNode会分配一个新的DataNode,保持replicas设定的数量 
    

    HDFS的HA(High Availability,高可用性)机制

      Hadoop2.X版本之前,NameNode是HDFS集群的单点故障点(SPOF)
      
      影响HDFS集群不可用主要包括以下两种情况:
            1:类似机器宕机这样的意外情况将导致集群不可用,只有重启NameNode之后才可使用
            2:计划内的软件或硬件升级(NameNode节点),将导致集群在短时间范围内不可用
                
      一个典型的HA集群,两个单独的机器配置为NameNode,在任何时候,一个NameNode处于活动状态,另一个处于待机状态,活动NameNode负责处理集群中所有客户端的操作,待机时仅仅作为一个Slave,保持足够的状态,如果有必要提供一个快速的故障转移
    
       为了提供快速的故障转移,必须保证备用节点有最新的集群中块的位置信息,为了达到这一点,DataNode节点需要配置两个NameNode的位置,同时发送块的位置信息和心跳信息到两个NameNode
    
      为了防止"脑裂场景"的出现,必须为共享存储配置至少一个fencing方法。在宕机期间,如果不能确定之间的活动节点已经放弃活动状态,fencing进程负责中断以前的活动节点编辑存储的共享访问,这可以防止任何进一步的修改名字空间.允许新的活动节点安全地进行故障转移
    
    Paste_Image.png

    HA架构解释如下:

    只有一个NameNode是Active,并且只有这个ActiveNameNode能提供服务,改变NameSpace。以后可以考虑让StandbyNameNode提供读服务
    
    提供手动Failover,在升级过程中,Failover在NameNode-DataNode之间写不变的情况下才能生效
    
    在之前的NameNode重新恢复之后,不能提供failback
      
    数据一致性比Failover更重要
    
    HA的设置和Failover都应该保证在两者操作错误或者配置错误的时候,不得导致数据损坏
    
    NameNode的短期垃圾回收不应该触发Failover
    
    DataNode会同时向NameNode Active和NameNode Standary汇报块的信息。NameNode Active和NameNode Standby 通过NFS备份MetaData信息到一个磁盘上面
    

    HDFS的federation机制

     简单的说,HDFS Federation就是使得HDFS支持多个名字空间,并且允许在HDFS中同时存在多个NameNode
    
     引入Federation的最主要原因是对HDFS系统中文件的隔离,Federation能够快速解决大部分单NameNode HDFS的问题
    

    HDFS Federation使用了多个独立的NameNode/NameSpace使得HDFS的命名服务能够水平扩展


    HDFS Federation中的NameNode之间是联盟关系,它们之间相互独立且不需要相互协调。HDFS Federation中的NameNode提供了名字空间和块关联功能.HDFS Federation中的DataNode被所有的NameNode用作公共存储块的地方.每一个DataNode都会向所在集群中所有的NameNode注册,并周期性的发送心跳和块信息报告,同时处理来自NameNode的指令

    块池(Block Pool)就是属于单个名字空间的一组Block
    
    Federation HDFS中有多组独立的块,同一个DataNode中可以存储属于多个块池的多个块。
    
    块池允许一个名字空间在不通知其他名字空间的情况下,为一个新的Block创建Block ID.同时,一个NameNode失效不会影响其下的DataNode为其他NameNode的服务
    

    在HDFS中,所有的更新、回滚都是以NameNode和BlockPool为单元发生的.即同HDFS Federation中不同的NameNode/BlockPool之间没有什么关系

    多个名字空间的管理问题

      在一个集群中需要唯一的名字空间还是多个名字空间,核心问题是名字空间中数据的共享和访问问题。
    
      使用全局唯一的名字空间是解决数据共享和访问的一种方法
    
      在多个名字空间下,还可以使用Client Side Mount Table方式做到数据共享和访问
    
    Paste_Image.png

    HDFS Federation中名字空间管理的基本原理:

          将各个名字空间挂载到全局mount-table中,就可以将数据到全局共享;
          同样,名字空间挂载到个人的mount-table中,就成为应用程序可见的名字空间视图
    

    维护HDFS
    追加数据

        1.Client调用fs的append操作
        2.向流对象写数据
        3.关闭流对象
    

    并行复制

      distcp(分布式复制)是用于大规模集群内部和集群之间复制的工具。它使用MapReduce实现文件分发、错误处理和恢复,以及报告生成。它把文件和目录的列表作为Map任务的输入,每个任务会完成源列表中部分文件的复制
        
      操作命令:
        hadoop distcp -overwrite -delete -i dir1 dir2
     
      参数如下:
            -delete:删除已经存在的目标文件,不会删除源文件。这个删除是通过FS Shell实现的。所以如果垃圾回收机制启动,删除的目标文件会进入trash
    
            -i:忽略失败.这个选项会比默认情况提供关于复制的更精确的统计,同时它还将保留失败复制操作的日志。这些日志信息可以用于调试
      
            -overwrite:覆盖目标。如果一个Map失败并且没有使用-i选项,那些复制失败的文件,以及这个分块任务中的所有文件都会被重新复制
    

    升级与回滚

        Hadoop升级分为两种:
                一种是集群布局不发生任何变化的,这种升级非常简单,类似安装一次新的Hadoop程序。
                另外一种是集群布局发送变化的
    

    两种升级升级都简单分为以下几步:

          1.在执行新一轮的升级前,要确保前一次升级已经完成
                    hadoop dfsadmin -upgradeProgress status
          2.进行数据的备份,以方便升级后对照,如果有问题可发现然后回滚版本
                  hadoop fs -lsr / > ~/namenode.log
                  hadoop fsck / >> ~/namenode.log
                  cp -r ${dfs.name.dir} ~/namenode_backup
        
          3.使用stop-all.sh关闭hadoop集群
          4.把${dfs.name.dir}目录下的所有内容复制到新配置的路径下,这是集群布局有变化的操作,如果没有新配置布局就不用这个操作了,单独启动新的主节点NameNode的hdfs进行更新操作
                ${NEW_HADOOP}/bin/start-dfs.sh -upgrade
            使用如下命令进行监控,查看是否升级完成
                 ${NEW_HADOOP}/bin/hadoop dfsadmin -upgradeProgress status
    
          5.把新版本的Hadoop程序和配置文件一起分发给集群里所有的机器,根据情况看是不是需要进行个别修改,没有特别的就不用改了。修改/etc/profile中的Hadoop环境变量,改成新版本Hadoop的指向。现在使用启动集群的start-all.sh命令来启动集群就行了
          6.使用fs -lsr 和fsck与namenode.log文件进行核对前后信息变化,如果没有问题,数据块体验也通过,就顺利完成升级,这时需要执行如下命令来最终确定升级完成和清理前版本数据
            hadoop dfsadmin -finalizeUpgrade
            rm -r ~/namenode_backup ~/namenode.log
          至此升级完成,不能再进行回滚操作,如果升级后发现数据不符,可以使用如下命令回滚版本
                stop-all.sh
                start-dfs.sh -rollback
    

    添加节点

        1.修改host。和普通的DataNode一样,添加NameNode的IP
        2.修改NameNode的配置文件conf/slaves。添加新增节点的Ip或主机名
        3.在新节点的机器上启动服务
            bin/hadoop-daemon.sh start datanode
            bin/hadoop-daemon.sh start tasktracker
        4.均衡Block
            bin/start-balancer.sh 
    
        为什么要执行start-balancer.sh操作呢?
        如果不执行start-balancer.sh操作.cluster会把新的数据都存放在新的节点上,这样会降低MapReduce的工作效率
    
      执行start-balancer.sh操作的优化如下
        1.设置平衡阀值,默认是10%,值越低各节点越平衡,但消耗时间也更长
        bin/start-balancer.sh -threshold 5
        2.设置balancer的带宽,默认只有1M/s.编辑hdfs-site.xml文件
        <property>
                    <name>dfs.balance.bandwidthPerSec</name>
                    <value>10485760</value>
        </property>
    

    删除节点

      1.集群配置
            修改conf/hdfs-site.xml文件
                <property>
                        <name>dfs.hosts.exclude</name>
                        <value>/data/soft/hadoop/conf/excludes</value>
                </property>
      2.确定要下架的机器
              dfs.hosts.exclude定义的文件内容为每个需要下线的机器,一行一个。这将阻止它们连接NameNode.
              例如/data/soft/hadoop/conf/excludes的内容如下:
                              ubuntu4
              这样就把ubuntu4这台设备从hadoop集群中删除了。还有一种方法可以实现ubuntu4设备从hadoop集群中删除,配置如下:
                <property>
                      <name>dfs.hosts.exclude</name>
                      <value>ubuntu4</value>
                </property>
                
      3.强制重新加载配置
            bin/hadoop dfsadmin -refreshNode
      它会在后台进行Block块的移动
      4.关闭节点
          bin/hadoop dfsadmin -report
        可以查看到现有集群上连接的节点信息
      5.再次编辑excludes文件
              一旦完成机器下架,下架的设备就可以从excludes文件移除了。登录要下架的机器,会发现DataNode进程没有了,但是TaskTracker依然存在,需要手动关闭
    

    HDFS权限管理

    hadoop分布式文件系统实现了一个和POSIX系统类似的文件和目录的权限模型。每个文件和目录有一个所有者(owner)和一个组(group)
    
     总的来说,文件或目录的权限就是它的模式。HDFS采用了UNIX表示和显示模式的习惯,包括使用八进制数来表示权限。当新建一个文件或目录,所有者即客户进程的用户,它的所属组是父目录的组
    
     HDFS并不提供创建用户身份、创建组或用户凭证等功能

    相关文章

      网友评论

      • Mr_Gao_:写的真好,受益了:+1:
      • 大雄blackie:感觉比较抽象,如何能够比较快速的全面深入的理解呢?
        Bloo_m: @大雄blackie 首先应该先理解HDFS的架构,再从架构出发去理解文件的读写,再去理解HDFS的其他一些特点,最后再去深入RPC流程(本人也是新手,仅是个人的学习思路)
      • 38faf480efd2:建议就是如果文字太长可以换行写,这样就不需要滚动查看后面内容。影响阅读!
        732656715ead:@小墨鱼3 用手机看的话,可以在手机浏览器中打开,横行看行了
        Bloo_m:@小墨鱼3 非常感谢你的建议,下次编写的时候一定注意!

      本文标题:HDFS详解

      本文链接:https://www.haomeiwen.com/subject/gocwpttx.html