第三讲 分布式文件系统HDFS

3.1 分布式文件系统HDFS简介

hadoop distributed file system

两大核心计算:大数据的分布式存储、大数据的分布式处理




hdfs文件权限所属用户 简述hdfs文件中权限有几类_hdfs文件权限所属用户


hdfs文件权限所属用户 简述hdfs文件中权限有几类_hdfs文件权限所属用户_02


HDFS目标:

兼容廉价的硬件设备;

实现流数据读写;(与传统DFS重要区别)

支持大数据集;

支持简单的模型;(只允许追加,不能修改,牺牲部分性能以提升批量处理特性)

强大的跨平台兼容性。

局限性:

不适合低延时数据访问;(HBase可以进行随机读写,满足实时性处理需求)

无法高效存储大量小文件;

不支持多用户写入及任意修改文件。

3.2 HDFS相关概念

块,也是为了分摊磁盘读写开销;但比普通文件系统的块大很多(默认64M)。

块的设计目的:面向大规模存储,降低分布式节点的寻址开销(三级寻址:元数据目录-数据节点-取数据)

块的设计也涉及MapReduce的处理。

抽象块的设计好处:支持大规模文件存储;简化系统设计;适合数据备份。

名称节点,主节点。负责元数据的存储,整个HDFS集群的管家。(数据目录,记录信息)

数据节点,具体负责存储数据。

元数据,文件是什么,文件被分成多少块,每个块和文件怎么映射,每个快被存储在哪个服务器上。

数据节点中的数据是保存在本地的linux文件系统中。

名称节点中的关键结构,FsImage,保存系统文件树;Editlog,记录对数据的创建、删除、重命名等操作。

FsImage,存储元数据:文件的复制等级,块大小以及组成文件的块,访问权限,修改和访问时间。

(FsImage没有具体记录块在哪个数据节点存储,是单独在内存中的一个区域进行维护的,构建了一个清单)

启动过程:


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_03


(这是一个优化处理,将更新处理放在Editlog,提升处理性能;但是随之带来问题,Editlog不断增大,这就用到了第二名称节点)

第二名称节点作用,名称节点的冷备份;对Editlog进行处理。

当Editlog不断增大,第二名称节点会定期和名称节点进行通信,在某个阶段会通知名称节点停止使用Editlog文件,名称节点则会停止写入Editlog,并生成一个新的edits.new,即又生成一个Editlog,会把新的更新等操作写入到edits.new,把旧的Editlog让第二名称节点取走。第二名称节点会通过Http Get的方式,从名称节点把FsImage和Editlog都下载到本地,然后在第二名称节点进行合并操作,得到一个新的FsImage,发给名称节点。名称节点就得到了更新后较大的FsImage,然后把edits.new更改为Editlog。通过这种操作,实现了不断增大的Editlog与FsImage的合并,也实现了冷备份的效果。

数据节点,关键是存和取。每个数据节点中的数据被保存在各自的本地linux文件系统中。

3.3 HDFS体系结构

采用主从结构,主节点(管家作用)提供数据目录服务。其它都是数据节点,负责具体数据存储。

客户端访问数据,首先访问名称节点,获取元数据信息,从而知道数据块具体的存储位置。

写数据时,首先访问名称节点,得到存储位置信息的指令,然后把相关的块存到相应的数据节点。

HDFS命令空间

只有一个命名空间,包含目录、文件、块,与传统文件系统一样,也是分级结构。

HDFS的通信协议是构建在TCP/IP之上,不同组件之间的通信协议稍有差别。

客户端和名称节点发起TCP连接,使用客户端的协议和名称节点进行交互;

名称节点和数据节点交互使用专门的数据节点协议;

客户端和数据节点交互通过远程调用RPC实现。

HDFS客户端实际上是一个库,对外界暴露HDFS文件系统接口,隐藏了后台实现的复杂性。

通过客户端可以实现文件打开、读写常见操作,可以通过java API或shell命令实现。

HDFS1.0局限性

命名空间限制,名称节点是保存在内存中,因此其容纳的数据对象(文件、块)的个数受到空间大小的限制。

性能的瓶颈,整个分布式系统文件的吞吐量,受限于单个名称节点的吞吐量。

隔离问题,集群中只有一个名称节点,只有一个命名空间,因此无法对不同的应用程序进行隔离。

集群的可用性,一旦这个唯一的名称节点发生故障,会导致整个集群变得不可用。(第二名称节点是冷备不是热备)

(名称节点发生故障,必须由第二名称节点经过一段时间的恢复,才可以对外提供服务)

HDFS2.0解决了单点故障,设置了两个名称节点,分区管理,热备。

3.4 HDFS存储原理

数据冗余保存,廉价机器频繁故障,每个数据块冗余保存(默认3份),伪分布式(单节点)的冗余因子只能是1。

加快了数据传输速度(并行访问),容易检查错误(互为备份有参照),保证数据可靠性(周期性探测保证副本数量)

数据保存策略

第一个副本,就近放在应用所在节点,如果是外部应用则随机选择CPU、磁盘充裕的节点;

第二个副本,放在和第一个副本所在不同机架上;

第三个副本,放在和第一个副本所在相同机架不同节点上;

第4/5/6……个副本根据随机算法放置。

数据读取

HDFS提供了一个API可以确定数据节点所属的机架ID,客户端也可以调用API获取自己所在的机架ID。

当客户端读取数据时,从名称节点获得数据块不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属机架ID,如有ID相同,则优先选择该数据节点上的副本进行读取,否则随机选择一个副本读取。

数据恢复

(标准的数据中心一般有三四千个数据节点)

名称节点出错,暂停服务一段时间,然后从第二名称节点恢复,最后才提供对外服务(HDFS1.0);HDFS2.0直接使用热备。

数据节点出错,数据节点会定期通过远程调用给名称节点发送心跳信息,一旦名称节点没有收到定期心跳,名称节点会将该数据节点标记为宕机(不可用),把所有存储在这个节点上的数据通过其它数据节点上的备份数据进行复制。

在数据节点负载不均衡的时候,也可以迁移数据节点上的副本。可以不断调整冗余数据副本的存放位置。

数据本身出错(磁盘损坏或其它情形),客户端读取到数据会通过校验码进行校验,校验码实在文件被创建时生成的。数据块和校验码放在同一目录。因此发现读取时计算出的校验码与原先保存的不一致时判断为数据错误,则通过冗余副本进行复制。

3.5 HDFS数据读取过程

3.5.1HDFS读数据过程


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_04


import导入一些包

定义一个类Chapter3

定义一个Main函数

声明一个环境配置变量conf,通过输入这个环境配置变量,系统将hdfs-site.xml和core-site.xml加载进来。从而获取重要参数:fs.DefaultFS(记录了分布式文件系统的地址,如hdfs://localhost:9000)

用文件系统FileSystem声明一个实例

声明一个Path类型的变量(文件打开路径)

设置文件的输入流inputStream来打开文件

读取

关闭

在Hadoop中有一个通用抽象文件基类FileSystem,可以通过继承它去实现很多具体子类。

如,可以被分布式文件系统HDFS继承,实现DistributedFileSystem子类;通过Http方式去访问相关文件;通过FTP的方式读写文件。

FileSystem常用的几个方法:open创建输入流,返回FSDataInputStream对象,其中封装了DFSInputStream是专门针对HDFS的实现;read创建输出流,返回FSDataOutputStream,其中封装了DFSOutputStream是专门针对HDFS的实现; close。

读数据过程:


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_05


第一步,打开文件,用FileSystem声明一个实例对象fs,即FileSystem.get(conf),对照底层的HDFS去实现。抽象基类是FileSystem,由于添加了环境变量conf,分布式文件系统底层的配置就会被调用,调进来后生成一个属于它的子类DistributedFileSystem,生成的fs实例是属于HDFS的实例对象,fs是跟分布式文件系统紧密相关的。(底层的转化封装是看不见的)

然后使用fs创建输入流,比如in=fs.open(new Path(URI)),URI就是输入文件的地址,打开后生成输入流FsDataInputStream,而且其中封装了DFSInputStream(Hadoop后台封装),实际上是DFSInputStream与名称节点交互,用户编程只和前面的FsDataInputStream交互。

第二步,DFSInputStream通过远程调用去和名称节点沟通,从而知道需要获取的数据块被保存在哪些节点,通过ClientProtocol.getBlocklocations这个方法去询问名称节点(需要的数据保存在哪个节点),名称节点会把文件的开始一部分位置信息(排序后)返回给刚才的调用。

第三步,客户端获得了输入流FsDataInputStream,就可以开始使用read函数读取数据,拿到了排序后的位置信息,选择距离最近的数据节点建立连接,然后去读数据。

第四步,把数据从数据节点读到客户端,读完了输入流FsDtaInputStream就要关闭和数据节点的连接。

第五步,获取数据块信息,继续读取数据。再去让输入流通过ClientProtocol.getBlocklocations这个方法去询问名称节点,下一个数据存在哪里,名称节点将返回相应的位置信息(数据节点列表-根据距离客户端的远近进行排序)。

第六步,输入流获得地址列表后,继续通过read函数,又开始和那些数据节点进行连接,读数据,读完后又关闭和那些节点的连接。

依次循环往复不断地读,直到完成所有数据块的读取。

第七步,关闭文件。调用输入流的关闭操作close。

这是读数据的全部过程。

3.5.2HDFS写数据过程


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_06


第一步,创建文件请求。用FileSystem实例化一个对象fs,这个fs的类型是DistributedFileSystem,它是继承自FileSystem的一个子类。然后创建一个输出流FsDataOutputStream,Hadoop在后台封装了DFSOutputStream,它是专门和名称节点打交道。

第二步,去询问名称节点。DFSOutputStream要执行RPC远程调用,请求名称节点在文件系统的命名空间中新建文件,名称节点会检查文件是否已存在、客户端是否有权限。检查通过后,创建文件,然后通过数组返回。

第三步,写数据。流水线复制。把数据拆分为分包,将分包放到DFSOutputStream对象的内部队列,然后DFSOutputStream向名称节点申请保存这些数据块的数据节点。

第四步,写入数据包。数据队列中的数据节点形成管道,队列里的分包会再打包成数据包 发到整个数据队列中的第一个数据节点,第一节点再发给第二节点,以此类推。即副本放在多个不同数据节点。

第五步,数据写入确认信息由数据管道中的最后一个数据节点依次向前回传,最后传给客户端。

第六步,关闭文件。

第七步,写操作完完成。

3.6 HDFS编程实践

HDFS的基本编程方法

Hadoop常见的操作:Shell命令和Java API,这两种方式都可以访问HDFS。

Hadoop安装后就包含了HDFS和

Reduce两个组件,所以不需要另外安装HDFS。

Hadoop启动三条命令。


hdfs文件权限所属用户 简述hdfs文件中权限有几类_hdfs文件权限所属用户_07


三种shell命令区别:


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_08


相关命令:


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_09


注意:系统安装了分布式文件系统HDFS后,还是有本地和分布式文件系统的区别,有些文件是存在了本地,有些文件是被存在了HDFS中。


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_10


可以通过Web界面去查看HDFS中的一些文件信息,如:http://localhost:50070 点击相关链接可以查看文件系统。

用得比较少,了解即可。

利用Java API与HDFS进行交互。(编程的方式)

实例:分布式文件系统HDFS上是否存在某个文件?

Ubuntu系统中安装和配置Eclipse:

1.放置配置文件到当前工程下面(Eclipse工作目录的bin文件夹下面)

2.编写实现代码

构建基础的编程环境,使用eclipse。

基本的命令:hadoop fs -xx #适用于本地系统以及HDFS系统,推荐

hadoop fs -ls

hadoop fs -cat

hadoop fs -mkdir

hadoop fs -cp #可以将本地文件上传(拷贝)到hdfs系统

使用Java开发必须加载jar包。

hadoop为HDFS和MapReduce提供了基础的支持,叫做hadoop common。一般在安装好的hadoop的文件夹里面,一般路径是

/usr/local/hadoop/share/hadoop

然后需要在eclipse的工程中导入外部jar包,右键工程属性-Java Build Path-Libraries- Add External JARS:


hdfs文件权限所属用户 简述hdfs文件中权限有几类_数据_11


检测伪分布式文件系统HDFS上是否存在input.txt文件?

第一步,把配置文件放到当前工程的bin目录下:

$ cp /usr/local/hadoop/etc/hadoop/{core-site.xml,hdfs-site.xml} /home/hadoop/workspace/Dblab/bin

(没有这一步,程序返回wrong fs)

第二步,编写实现代码:

shell命令和java api执行的功能是等价的,取决于哪种方法效率更高。