大数据学习笔记(四)——分布式文件系统HDFS

第四章 分布式文件系统HDFS

4.1 分布式文件系统

相对于传统的本地文件系统而言,分布式文件系统(Distributed File System)是一种通过网络实现文件在多台主机上进行分布式存储的文件系统,分布式文件系统的设计一般采用“客户端/服务器”(Client/Server)模式,客户端以特定的通信协议通过网络与服务器建立连接,提出文件访问请求,客户端和服务器可以通过设置访问权来限制请求方对底层数据存储块的访问。

4.1.1 计算机集群结构

普通文件系统与分布式文件系统的对比:

  • 普通文件系统只需要单个计算机节点就可以完成文件的存储和处理,单个计算机节点由处理器、内存、高速缓存和本地磁盘构成;
  • 分布式文件系统把文件分布存储到多个计算机节点上,成千上万的计算机节点构成计算机集群,与之前使用多个处理器和专用高级硬件的并行化处理装置不同的是,目前的分布式文件系统所采用的计算机集群都是由普通硬件构成的,这就大大降低了硬件上的开销。

计算机集群的基本架构如下图所示,集群中的计算机节点存放在机架(Rack)上,每个机架可以存放8~64个计算机节点同一机架上的不同节点之间通过网络互连(常采用吉比特以太网),多个不同机架之间采用另一级网络或交换机互连
在这里插入图片描述

4.1.2 分布式文件系统的结构

普通文件系统与分布式文件系统的对比:

  • 普通文件系统一般会把磁盘空间划分为每512字节一组,称为“磁盘块”,它是文件系统读写操作的最小单位,文件系统的(Block)通常是磁盘块的整数倍,即每次读写的数据量必须是磁盘块大小的整数倍;
  • 分布式文件系统也采用了的概念,文件被分成若干个块进行存储,块是数据读写的基本单元,只不过分布式文件系统的块要比普通文件系统中的块大很多,比如,HDFS默认的一个块的大小是64MB,而且与普通文件系统不同的是,在分布式文件系统中,如果一个文件小于一个数据块的大小,它并不占用整个数据块的存储空间

分布式文件系统在物理结构上是由计算机集群中的多个节点构成的,如下图所示,这些节点分为两类:一类叫“主节点”(Master Node),或者也被称为“名称节点"(NameNode);另一类叫“从节点"(Slave Node),或者也被称为“数据节点"(DataNode):
在这里插入图片描述

  • 名称节点负责文件和目录的创建、删除和重命名等,同时管理着数据节点和文件块的映射关系,因此客户端只有访问名称节点才能找到请求的文件块所在的位置,进而到相应位置读取所需文件块;
  • 数据节点负责数据的存储和读取,在存储时,由名称节点分配存储位置,然后由客户端把数据直接写入相应数据节点,在读取时,客户端从名称节点获得数据节点和文件块的映射关系,然后就可以到相应位置访问文件块。数据节点也要根据名称节点的命令创建、删除数据块和冗余复制

计算机集群中的节点可能发生故障,因此为了保证数据的完整性,分布式文件系统通常采用多副本存储,文件块会被复制为多个副本,存储在不同的节点上,而且存储同一文件块的不同副本的各个节点会分布在不同的机架上,这样在单个节点出现故障时,就可以快速调用副本重启单个节点上的计算过程,而不用重启整个计算过程,整个机架出现故障时也不会丢失所有文件块。文件块的大小和副本个数通常可以由用户指定

分布式文件系统是针对大规模数据存储而设计的,主要用于处理大规模文件,如TB级文件,处理过小的文件不仅无法充分发挥其优势,而且会严重影响到系统的扩展和性能

4.1.3 分布式文件系统的设计需求

分布式文件系统的设计目标主要包括透明性、并发控制、可伸缩性、容错以及安全需求等,但是在具体实现中,不同产品实现的级别和方式都有所不同,下表给出了分布式文件系统的设计需求及其具体含义,以及HDFS对这些指标的实现情况:

设计需求 含义 HDFS的实现情况
透明性 具备访问透明性、位置透明性、性能和伸缩透明性。访问透明性是指用户不需要专门区分哪些是本地文件,哪些是远程文件,用户能够通过相同的操作来访问本地文件和远程文件资源。位置透明性是指在不改变路径名的前提下,不管文件副本数量和实际存储位置发生何种变化,对用户而言都是透明的,用户不会感受到这种变化,只需要使用相同的路径名就始终可以访问同一个文件。性能和伸缩透明性是指系统中节点的增加或减少以及性能的变化对用户而言是透明的,用户感受不到什么时候一个节点加入或退出了。 只能提供一定程度的访问透明性,完全支持位置透明性、性能和伸缩透明性
并发控制 客户端对于文件的读写不应该影响其他客户端对同一个文件的读写 机制非常简单,任何时间都只允许有一个程序写入某个文件
文件复制 一个文件可以拥有在不同位置的多个副本 HDFS采用了多副本机制
硬件和操作系统的异构性 可以在不同的操作系统和计算机上实现同样的客户端和服务器端程序 采用Java语言开发,具有很好的跨平台能力
可伸缩性 支持节点的动态加入或退出 建立在大规模廉价机器上的分布式文件系统集群,具有很好的可伸缩性
容错 保证文件服务在客户端或者服务端出现问题的时候能正常使用 具有多副本机制和故障自动检测、恢复机制
安全 保障系统的安全性 安全性较弱

4.2 HDFS简介

HDFS支持流数据读取处理超大规模文件,并能够运行在由廉价的普通机器组成的集群上,这主要得益于HDFS在设计之初就充分考虑了实际应用环境的特点,那就是,硬件出错在服务器集群中是一种常态,而不是异常,因此,HDFS在设计上采取了多种机制保证在硬件出错的环境中实现数据的完整性

总体而言,HDFS要实现以下目标:

  • 兼容廉价的硬件设备:在成百上千台廉价服务器中存储数据,常会出现节点失效的情况,因此HDFS设计了快速检测硬件故障和进行自动恢复的机制,可以实现持续监视、错误检查、容错处理和自动恢复,从而使得在硬件出错的情况下也能实现数据的完整性;
  • 流数据读写:普通文件系统主要用于随机读写以及与用户进行交互,而分布式文件系统HDFS则是为了满足批量数据处理的要求而设计的,因此为了提高数据吞吐率,HDFS放松了一些POSIX的要求,从而能够以流式方式来访问文件系统数据
  • 大数据集:HDFS中的文件通常可以达到GB甚至TB级别,一个数百台机器组成的集群里面可以支持千万级别这样的文件;
  • 简单的文件模型:HDFS采用了“一次写入、多次读取”的简单文件模型,文件一旦完成写入,关闭后就无法再次写入,只能被读取
  • 强大的跨平台兼容性:HDFS是采用Java语言实现的,具有很好的跨平台兼容性,支持JVM(Java Virtual Machine)的机器都可以运行HDFS。

HDFS特殊的设计,在实现上述优良特性的同时,也使得自身具有一些应用局限性,主要包括以下几个方面:

  • 不适合低延迟数据访问:HDFS主要是面向大规模数据批量处理而设计的,采用流式数据读取,具有很高的数据吞吐率,但是,这也意味着较高的延迟,因此,HDFS不适合用在需要较低延迟(如数十毫秒)的应用场合,对于低延迟要求的应用程序而言,HBase是一个更好的选择;

  • 无法高效存储大量小文件:小文件是指文件大小小于一个块的文件,HDFS无法高效存储和处理大量小文件,过多小文件会给系统扩展性和性能带来诸多问题:

    ①HDFS采用名称节点(NameNode)来管理文件系统的元数据,这些元数据被保存在内存中,从而使客户端可以快速获取文件实际存储位置,通常,每个文件、目录和块大约占150字节,如果有1000万个文件,每个文件对应一个块,那么,名称节点至少要消耗3GB的内存来保存这些元数据信息。很显然,这时元数据检索的效率就比较低了,需要花费较多的时间找到一个文件的实际存储位置。而且,如果继续扩展到数十亿个文件时,名称节点保存元数据所需要的内存空间就会大大增加,以现有的硬件水平,是无法在内存中保存如此大量的元数据的;

    ②用MapReduce处理大量小文件时,会产生过多的Map任务,线程管理开销会大大增加,因此处理大量小文件的速度远远低于处理同等大小的大文件的速度;

    ③访问大量小文件的速度远远低于访问几个大文件的速度,因为访问大量小文件,需要不断从一个数据节点跳到另一个数据节点,严重影响性能。

  • 不支持多用户写入及任意修改文件:HDFS只允许一个文件有一个写入者,不允许多个用户对同一个文件执行写操作,而且只允许对文件执行追加操作,不能执行随机写操作。

4.3 HDFS的相关概念

4.3.1 块

在普通文件系统中,为了提高磁盘读写效率,一般以数据块为单位,而不是以字节为单位。比如,机械式硬盘(磁盘的一种)包含了磁头和转动部件,在读取数据时有一个寻道的过程,通过转动盘片和移动磁头的位置,来找到数据在机械式硬盘中的存储位置,然后才能进行读写。在IO开销中,机械式硬盘的寻址时间是最耗时的部分,一旦找到第一条记录,剩下的顺序读取效率是非常高的。因此,以块为单位读写数据,可以把磁盘寻道时间分摊到大量数据中

分布式文件HDFS也同样采用了块的概念,默认的一个块大小是64MB,在HDFS中的文件会被拆分成多个块,每个块作为独立的单元进行存储。普通文件系统的块一般只有几千字节(byte),而HDFS在块的大小的设计上要远远大于普通文件系统,HDFS这么做的原因,是为了最小化寻址开销

HDFS寻址开销不仅包括磁盘寻道开销,还包括数据块的定位开销。当客户端需要访问一个文件时,首先从名称节点获得组成这个文件的数据块的位置列表,然后根据位置列表获取实际存储各个数据块的数据节点的位置,最后数据节点根据数据块信息在本地Linux文件系统中找到对应的文件,并把数据返回给客户端。设计一个比较大的块,可以把上述寻址开销分摊到较多的数据中,降低了单位数据的寻址开销。因此,HDFS在文件块大小设置上要远远大于普通文件系统,以期在处理大规模文件时能够获得更好的性能。当然,块的大小也不宜设置过大,因为,通常MapReduce中的Map任务一次只处理一个块中的数据,如果启动的任务太少,就会降低作业并行处理速度。

HDFS采用抽象的块概念可以带来以下几个明显的好处:

  • 支持大规模文件存储:文件以块为单位进行存储,一个大规模文件可以被分拆成若干个文件块,不同的文件块可以被分发到不同的节点上,因此一个文件的大小不会受到单个节点的存储容量的限制,可以远远大于网络中任意节点的存储容量;
  • 简化系统设计:首先,大大简化了存储管理,因为文件块大小是固定的,这样就可以很容易计算出一个节点可以存储多少文件块;其次,方便了元数据的管理,元数据不需要和文件块一起存储,可以由其他系统负责管理元数据;
  • 适合数据备份:每个文件块都可以冗余存储到多个节点上,大大提高了系统的容错性和可用性。

4.3.2 名称节点

在HDFS中,名称节点(NameNode)负责管理分布式文件系统的命名空间(Namespace),保存了两个核心的数据结构,即FsImage和EditLog:

  • FsImage用于维护文件系统树以及文件树中所有的文件和目录的元数据,FsImage文件包含文件系统中所有文件和目录inode的序列化形式,每个inode是一个文件或目录的元数据的内部表示。对于文件,存储文件的复制等级、修改和访问时间、访问权限、块大小以及组成文件的块;对于目录,则存储目录的修改时间、权限和配额元数据。FsImage文件没有记录文件包含的每个块存储在哪个数据节点,而是由名称节点把这些映射信息保留在内存中,当数据节点加入HDFS集群时,数据节点会把自己所包含的块列表告知给名称节点,此后会定期执行这种告知操作,以确保名称节点的块映射是最新的;
  • 操作日志文件EditLog中记录了所有针对文件的创建、删除、重命名等操作。
    在这里插入图片描述

名称节点记录了每个文件中各个块所在的数据节点的位置信息,但是并不持久化存储这些信息,而是在系统每次启动时扫描所有数据节点重构得到这些信息

名称节点在启动时,会将FsImage的内容加载到内存当中,然后执行EditLog文件中的各项操作,使得内存中的元数据和实际保持同步,这个操作完成以后,就会重新创建一个记录最新元数据信息的FsImage文件,以及一个空的EditLog文件。

名称节点在启动的过程中处于“安全模式”,只能对外提供读操作,无法提供写操作。启动过程结束后,系统就会退出安全模式,进入正常运行状态,对外提供读写操作。

名称节点启动成功并进入正常运行状态以后,HDFS中的更新操作都会被写入到EditLog,而不是直接写入FsImage,这是因为对于分布式文件系统而言,FsImage文件通常都很庞大(一般都是GB级别以上), 如果所有的更新操作都直接往FsImage文件中添加,那么系统就会变得非常缓慢,相对而言, EditLog通常都要远远小于FsImage,更新操作写入到EditLog是非常高效的。

4.3.3 第二名称节点

在名称节点运行期间,HDFS 会不断发生更新操作,这些更新操作都是直接被写入到EditLog文件,所以EditLog文件也会逐渐变大,在名称节点运行期间,不断变大的EditLog文件通常对于系统性能不会产生显著影响,但是当名称节点重启时,需要将FsImage加载到内存中,然后逐条执行EditLog中的记录,使得FsImage保持最新,因此,如果EditLog很大,就会导致整个过程变得非常缓慢,使得名称节点在启动过程中长期处于“安全模式”,无法正常对外提供写操作,影响了用户的使用。

为了有效解决EditLog逐渐变大带来的问题,HDFS在设计中采用了第二名称节点(SecondaryNameNode),第二名称节点是HDFS架构的一个重要组成部分,它的工作情况如下:
在这里插入图片描述

  1. SecondaryNameNode会定期和NameNode通信,请求其停止使用EditLog文件,暂时将新的写操作写到一个新的文件EditLog.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别;
  2. SecondaryNameNode通过HTTP GET方式从NameNode上获取到FsImage和EditLog文件,并下载到本地的相应目录下;
  3. SecondaryNameNode将下载下来的FsImage载入到内存,然后一条一条地执行EditLog文件中的各项更新操作,使得内存中的FsImage保持最新,这个过程就是EditLog和FsImage文件合并;
  4. SecondaryNameNode执行完上一步操作之后,会通过post方式将新的FsImage文件发送到NameNode节点上;
  5. NameNode将从SecondaryNameNode接收到的新的FsImage替换旧的FsImage文件,同时将EditLog.new替换EditLog文件,通过这个过程EditLog就变小了。

由上述工作过程可以看到,第二名称节点具有两个方面的功能:

  • 可以完成EditLog与FsImage的合并操作,减小EditLog文件大小,缩短名称节点重启时间;
  • 可以作为名称节点的“检查点”,保存名称节点中的元数据信息。

4.3.4 数据节点

数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块的列表。

每个数据节点中的数据会被保存在各自节点的本地Linux文件系统中

4.4 HDFS体系结构

4.4.1 概述

HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群包括一个名称节点(NameNode)和若干个数据节点(DataNode),名称节点作为中心服务器,负责管理文件系统的命名空间及客户端对文件的访问,集群中的数据节点一般是一个节点运行一个数据节点进程,负责处理文件系统客户端的读/写请求,在名称节点的统一调度下进行数据块的创建、删除和复制等操作。每个数据节点会周期性地向名称节点发送“心跳"信息,报告自己的状态,没有按时发送心跳信息的数据节点会被标记为“宕机”,不会再给它分配任何I/O请求。

用户在使用HDFS时,仍然可以像在普通文件系统中那样,使用文件名去存储和访问文件。实际上,在系统内部,一个文件会被切分成若干个数据块,这些数据块被分布存储到若干个数据节点上。当客户端需要访问一个文件时,首先把文件名发送给名称节点,名称节点根据文件名找到对应的数据块(一个文件可能包括多个数据块),再根据每个数据块信息找到实际存储各个数据块的数据节点的位置,并把数据节点位置发送给客户端,最后客户端直接访问这些数据节点获取数据。在整个访问过程中,名称节点并不参与数据的传输。这种设计方式,使得个文件的数据能够在不同的数据节点上实现并发访问,大大提高了数据访问速度。
在这里插入图片描述

HDFS采用Java语言开发,因此任何支持JVM的机器都可以部署名称节点和数据节点。在实际部署时,通常在集群中选择一台性能较好的机器作为名称节点,其他机器作为数据节点。当然,一台机器可以运行任意多个数据节点,甚至名称节点和数据节点也可以放在一台机器上行,不过,很少在正式部署中采用这种模式。HDFS集群中只有唯一个名称节点,该节点负责所有元数据的管理,这种设计大大简化了分布式文件系统的结构,可以保证数据不会脱离名称节点的控制,同时,用户数据也永远不会经过名称节点,这大大减轻了中心服务器的负担,方便了数据管理。

4.4.2 HDFS命名空间管理

HDFS的命名空间包含目录、文件和块命名空间管理是指命名空间支持对HDFS中的目录、文件和块做类似普通文件系统的创建、修改、删除等基本操作。在当前的HDFS体系结构中,在整个HDFS集群中只有一个命名空间,并且只有唯一个名称节点, 该节点负责对这个命名空间进行管理。

HDFS使用的是传统的分级文件体系,因此用户可以像使用普通文件系统一样,创建、删除目录和文件,在目录间转移文件、重命名文件等。但是,HDFS还没有实现磁盘配额和文件访问权限等功能,也不支持文件的硬连接和软连接(快捷方式)

4.4.3 通信协议

HDFS是一个部署在集群上的分布式文件系统,因此很多数据需要通过网络进行传输。所有的HDFS通信协议都是构建在TCP/IP协议基础之上的客户端通过一个可配置的端口向名称节点主动发起TCP连接,并使用客户端协议与名称节点进行交互名称节点和数据节点之间则使用数据节点协议进行交互客户端与数据节点的交互是通过RPC(Remote Procedure Call)来实现的。在设计上,名称节点不会主动发起RPC,而是响应来自客户端和数据节点的RPC请求

4.4.4 客户端

客户端是用户操作HDFS最常用的方式,HDFS在部署时都提供了客户端,HDFS客户端是一个库,暴露了HDFS文件系统接口,这些接口隐藏了HDFS实现中的大部分复杂性。严格来说,客户端并不算是HDFS的一部分。客户端可以支持打开、读取、写入等常见的操作,并且提供了类似Shell的命令行方式来访问HDFS中的数据,此外,HDFS也提供了Java API,作为应用程序访问文件系统的客户端编程接口

4.4.5 HDFS体系结构的局限性

HDFS只设置唯一一个名称节点,这样做虽然大大简化了系统设计,但也带来了一些明显的局限性,具体如下:

  • 命名空间的限制:名称节点是保存在内存中的,因此,名称节点能够容纳的对象(文件、块)的个数会受到内存空间大小的限制;
  • 性能的瓶颈:整个分布式文件系统的吞吐量,受限於单个名称节点的吞吐量;
  • 隔离问题:由于集群中只有一个名称节点,只有一个命名空间,因此,无法对不同应用程序进行隔离;
  • 集群的可用性:一旦这个唯一的名称节点发生故障,会导致整个集群变得不可用。

4.5 HDFS的存储原理

4.5.1 数据的冗余存储

作为一个分布式文件系统,为了保证系统的容错性和可用性,HDFS采用了多副本方式对数据进行冗余存储,通常一个数据块的多个副本会被分布到不同的数据节点上,如下图所示:
在这里插入图片描述

多副本存储方式有以下三个优点:

  • 加快数据传输速度:当多个客户端需要同时访问同一个文件时,可以让各个客户端分别从不同的数据块副本中读取数据,这就大大加快了数据传输速度;
  • 容易检查数据错误:HDFS的数据节点之间通过网络传输数据,采用多个副本可以很容易判断数据传输是否出错;
  • 保证数据的可靠性:即使某个数据节点出现故障失效,也不会造成数据丢失。

4.5.2 数据存储策略

4.5.2.1 数据存放

为了提高数据的可靠性与系统的可用性,以及充分利用网络带宽,HDFS采用了以机架(Rack)为基础的数据存放策略,一个HDFS集群通常包含多个机架,不同机架之间的数据通信需要经过交换机或者路由器,同个机架中不同机器之间的通信则不需要经过交换机和路由器,这意味着同一个机架中不同机器之间的通信要比不同机架之间机器的通信带宽大。

HDFS默认每个数据节点都是在不同的机架上,这种方法会存在一个缺点,那就是写入数据的时候不能充分利用同一机架内部机器之间的带宽,但是,与这点缺点相比,这种方法也带来了更多很显著的优点:

  • 可以获得很高的数据可靠性,即使一个机架发生故障,位于其他机架上的数据副本仍然是可用的;
  • 在读取数据的时候,可以在多个机架上并行读取数据,大大提高了数据读取速度
  • 可以更容易地实现系统内部负载均衡和错误处理

HDFS默认的冗余复制因子是3,每一个文件块会被同时保存到3个地方,其中有两份副本放在同一个机架的不同机器上面,第三个副本放在不同机架的机器上面,这样既可以保证机架发生异常时的数据恢复,也可以提高数据读写性能,一般而言,HDFS副本的放置策略如下:
在这里插入图片描述

  • 如果是在集群内发起写操作请求,则把第一个副本放置在发起写操作请求的数据节点上,实现就近写入数据,如果是来自集群外部的写操作请求,则从集群内部挑选一台磁盘不太满、CPU不太忙的数据节点,作为第一个副本的存放地;
  • 第二个副本会被放置在与第一个副本不同的机架的数据节点上;
  • 第三个副本会被放置在与第一个副本相同的机架的其他节点上;
  • 如果还有更多的副本,则继续从集群中随机选择数据节点进行存放。

4.5.2.2 数据读取

HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端也可以调用API获取自己所属的机架ID。当客户端读取数据时,从名称节点获得数据块不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属的机架ID,当发现某个数据块副本对应的机架ID和客户端对应的机架ID相同时,就优先选择该副本读取数据,如果没有发现,就随机选择一个副本读取数据。

4.5.2.3 数据复制

HDFS的数据复制采用了流水线复制的策略,大大提高了数据复制过程的效率。当客户端要往HDFS中写入一个文件时,这个文件会首先被写入本地,并被切分成若干个块,每个块的大小是由HDFS的设定值来决定的。每个块都向HDFS集群中的名称节点发起写请求,名称节点会根据系统中各个数据节点的使用情况,选择一个数据节点列表返回给客户端,然后客户端就把数据首先写入列表中的第一个数据节点,同时把列表传给第一个数据节点,当第一个数据节点接收到一个块的数据的时候,将其写入本地,并且向列表中的第二个数据节点发起连接请求,把自己已经接收到的数据和列表传给第二个数据节点,当第二个数据节点接收到数据的时候,将其写入本地,并且向列表中的第三个数据节点发起连接请求,依次类推,列表中的多个数据节点形成一条数据复制的流水线,最后,当文件写完的时候,数据复制也同时完成

4.5.3 数据错误与恢复

HDFS具有较高的容错性,可以兼容廉价的硬件,它把硬件出错看作一种常态,而不是异常,并设计了相应的机制检测数据错误和进行自动恢复,主要包括以下几种情形:

  • 名称节点出错:名称节点保存了所有的元数据信息,其中,最核心的两大数据结构是FsImageEditlog,如果这两个文件发生损坏,那么整个HDFS文件系统将失效。HDFS采用两种机制来确保名称节点的安全:第一,把名称节点上的元数据信息同步存储到其他文件系统(比如远程挂载的网络文件系统NFS)中;第二,运行一个第二名称节点,当名称节点宕机以后,可以把第二名称节点作为一种弥补措施,利用第二名称节点中的元数据信息进行系统恢复。一般会把上述两种方式结合使用,当名称节点发生宕机时,首先到远程挂载的网络文件系统中获取备份的元数据信息,放到第二名称节点上进行恢复,并把第二名称节点作为名称节点来使用;

  • 数据节点出错:每个数据节点会定期向名称节点发送“心跳”信息,向名称节点报告自己的状态。当数据节点发生故障,或者网络发生断网时,名称节点就无法收到来自一些数据节点的心跳信息,这时,这些数据节点就会被标记为“宕机”,节点上面的所有数据都会被标记为“不可读”,名称节点不会再给它们发送任何I/O请求。这时,有可能出现一种情形,即由于一些数据节点的不可用,会导致一些数据块的副本数量小于冗余因子。名称节点会定期检查这种情况,一旦发现某个数据块的副本数量小于冗余因子,就会启动数据冗余复制,为它生成新的副本。HDFS和其它分布式文件系统的最大区别就是可以调整冗余数据的位置

  • 数据出错:网络传输和磁盘错误等因素,都会造成数据错误。客户端在读取到数据后,会采用md5和sha1对数据块进行校验,以确定读取到正确的数据。在文件被创建时,客户端就会对每一个文件块进行信息摘录,并把这些信息写入到同一个路径的隐藏文件里面。当客户端读取文件的时候,会先读取该信息文件,然后,利用该信息文件对每个读取的数据块进行校验,如果校验出错,客户端就会请求到另外一个数据节点读取该文件块,并且向名称节点报告这个文件块有错误,名称节点会定期检查并且重新复制这个块。

4.6 HDFS的数据读写过程

HDFS的读取数据过程请参照:HDFS的读取数据过程详解 + Java代码实现

HDFS的写入数据过程请参照:HDFS的写入数据过程详解 + Java代码实现

4.7 HDFS操作常用Shell命令

请在伪分布式或分布式模式配置下的Hadoop上使用Shell命令操作HDFS,Hadoop的伪分布式模式配置请参照:Linux系统Hadoop伪分布式模式配置

HDFS支持很多Shell命令,例如hadoop fshdfs dfs都是HDFS最常用的Shell命令,两者功能和用法相同,都可以查看HDFS文件系统的目录结构、上传和下载数据、创建文件等。

我们先来看一看如何查看命令的使用方法,打开Linux终端,启动Hadoop:

start-dfs.sh

通过执行以下命令查看hadoop fshdfs dfs命令支持哪些操作:

hadoop fs

hdfs dfs

它们的执行结果相同,如下(这里只列出部分输出):
在这里插入图片描述
可以查看某个命令的具体用法,比如可以通过以下命令查看put命令的用法:

hdfs dfs -help put

hadoop fs -help put

输出结果如下:
在这里插入图片描述
HDFS操作的一些常用Shell命令请参照:Linux系统HDFS操作常用Shell命令

4.8 HDFS的Web管理界面

在配置好Hadoop集群之后,可以通过浏览器登录"htp://[NameNodeIP]:50070”访问HDFS文件系统,其中,[NameNodeIP]表示名称节点的IP地址,例如,我们在本地机器上完成Hadoop伪分布式安装后,可以登录http://localhost:50070来查看文件系统信息,如下:
在这里插入图片描述
通过该Web界面,我们可以查看当前文件系统中各个节点的分布信息,浏览名称节点上的存储、登录等日志,以及下载某个数据节点上某个文件的内容。该Web界面的所有功能都能通过Hadoop提供的Shell命令或者Java API来等价实现

4.9 HDFS编程实践

4.9.1 HDFS常用Java API

Hadoop采用Java语言开发,提供了Java API与HDFS进行交互,HDFS的Shell命令,在执行时实际上会被系统转换成Java API进行调用

Hadoop官方网站提供了完整的Hadoop API文档:http://hadoop.apache.org/docs/stable/api/,想要深入学习Hadoop编程,可以访问Hadoop官网查看各个API的功能和用法,在这里只介绍一些常用的Java API:

Java API 介绍
org.apache.hadoop.fs.FileSystem 一个通用文件系统的抽象基类,可以被分布式文件系统继承。所有可能使用Hadoop文件系统的代码都要使用到这个类。Hadoop为FileSystem这个抽象类提供了多种具体的实现,如LocalFileSystem 、DistributedFileSystem 、HftpFileSystem 、HsftpFileSystem、HarFileSystem 、KosmosFileSystem 、FtpFileSystem, NativeS3FileSystem
org.apache.hadoop.fs.FileStatus 一个接口,用于向客户端展示系统中文件和目录的元数据,具体包括文件大小、块大小、副本信息、所有者、修改时间等,可通过FileSystem.listStatus()方法获得具体的实例对象
org.apache.hadoop.fs.FSDataInputStream 文件输入流,用于读取Hadoop文件
org.apache.hadoop.fs.FSDataOutputStream 文件输出流,用于写Hadoop文件
org.apache.hadoop.conf.Configuration 访问配置项,但是如果配置项的值,在core-site.xml中有对应的配置,则以core-site.xml为准
org.apache.hadoop.fs.Path 用于表示Hadoop文件系统中的一个文件或者一个目录的路径
org.apache.hadoop.fs.PathFilter 一个接口, 通过实现方法PathFilter.accept(Path path)来判定是否接收路径path表示的文件或目录

4.9.2 编写Java应用程序的准备工作

因为Hadoop采用Java语言开发,所以我们首先要在Linux系统上安装Java环境,具体步骤请参照:Linux系统安装Java环境

在Linux系统上安装Java环境成功以后,我们使用软件Eclipse编写Java程序,我们需要在Linux系统上安装Eclipse,具体步骤请参照:Linux系统安装Eclipse

在Linux系统上安装Eclipse成功以后,就是一系列常规操作,打开Eclipse,创建一个项目等等,同学们应该对它比较熟悉了,具体用法网上一大把,就不多赘述了,在这里介绍一下如何为我们的项目添加需要的JAR包,这些JAR包中包含了可以访问HDFS的Java API。

在添加JAR包之前,我们可以新建一个Library来管理我们要添加的JAR包,因为我们需要添加的JAR包比较多,直接添加会显得比较混乱,具体步骤请参照:Eclipse技巧——通过Library管理自己的JAR包

我们需要添加的JAR包都位于Hadoop的安装目录下,找到自己Hadoop的安装目录,我的安装目录是/usr/local/hadoop/,所以我需要添加的JAR包都位于/usr/local/hadoop//share/hadoop/目录下,该目录的内容如下:
在这里插入图片描述
为了编写能够与HDFS交互的Java应用程序,一般需要向项目中添加以下JAR包:

  • /usr/local/hadoop//share/hadoop/common/目录下的hadoop-common-2.7.7.jarhadoop-nfs-2.7.7.jar
  • /usr/local/hadoop//share/hadoop/common/lib/目录下的所有JAR包
  • /usr/local/hadoop//share/hadoop/hdfs/目录下的hadoop-hdfs-2.7.7.jarhadoop-hdfs-nfs-2.7.7.jar
  • /usr/local/hadoop//share/hadoop/hdfs/lib/目录下的所有JAR包

4.9.3 编写Java应用程序

在学习完HDFS的结构、原理以及功能后,Java代码实现相关操作也必不可少,因为这样可以帮助我们加深理解,这里列出一些Java代码对HDFS相关操作的具体实现:

HDFS的写入数据过程详解 + Java代码实现

HDFS的读取数据过程详解 + Java代码实现

HDFS判断文件或目录是否存在——Shell命令实现 + Java代码实现

需要注意的是,在上述Java代码对HDFS相关操作的具体实现中,关于配置项的加载,可以不采用set()传参方法进行配置,我们可以放置配置文件到当前工程下面,即把集群上的配置文件core-site.xml和hdfs-site.xml拷贝一份放到当前工程项目下也就是Eclipse工作目录的bin文件夹下面,这样可以避免每次编写Java代码时都需要进行配置,可以这样做是因为在创建Configuration对象时会自动加载当前工程下的配置文件。

关于配置文件core-site.xml和hdfs-site.xml的具体配置请参照:Linux系统Hadoop伪分布式模式配置

4.9.4 Java应用程序在Hadoop平台上的部署

我们在编写Java应用程序后,可以直接在Eclipse上编译运行,也可以通过生成JAR包的方式把它部署到Hadoop平台上运行,生成Java应用程序的JAR包的具体步骤请参照:Eclipse技巧——生成自己的JAR包,不过需要注意的是,我们新建的用来存放JAR包的文件夹应该位于Hadoop安装目录下。

在生成JAR包后,我们可以直接打开Linux终端,通过下列命令在Hadoop平台上运行已经部署好的程序:

  1. 启动Hadoop:
    start-dfs.sh 
    
  2. 进入JAR包所在目录:
    cd JAR包所在目录 
    
  3. 使用hadoop jar命令运行程序:
    hadoop jar JAR包名称.jar 
    

4.10 学习资源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章