第3章 HDFS技术

知识储备

  • UNIX或Linux基本操作命令
  • Java基础知识

学习目标

  • 理解HDFS的主要特性
  • 理解HDFS架构
  • 熟悉HDFS的Shell操作
  • 了解HDFS中API的使用
  • 了解Hadoop的RPC通信机制

一个只有500 GB的单机节点无法一次性处理连续的PB级的数据,那么应如何解决这个问题呢?这就需要把大规模数据集分别存储在多个不同的节点的系统中,实现跨网络的多个节点资源的文件系统,即分布式文件系统(Distributed File System)。它与普通磁盘文件系统有很多相近的地方,但由于整个架构是在网络上,而网络编程的复杂性和网络的不可靠性势必造成分布式文件系统要比普通的磁盘系统复杂。


3.1 HDFS的特点

HDFS用来设计存储大数据,并且是分布式存储,所以所有特点都与大数据与分布式有关,其特点可概括如下。
1.简单一致性
对HDFS的大部分应用都是一次写入多次读(只能有一个writer,但可以有多个reader),如搜索引擎程序,一个文件写入后就不能修改了。因此写入HDFS的文件不能修改或编辑,如果一定要进行这样的操作,只能在HDFS外修改好了再上传。
2.故障检测和自动恢复
企业级的HDFS文件由数百甚至上千个节点组成,而这些节点往往是一些廉价的硬件,这样故障就成了常态。HDFS具有容错性(fault-tolerant),能够自动检测故障并迅速恢复,因此用户察觉不到明显的中断。
3.流式数据访问
Hadoop的访问模式是一次写多次读,而读可以在不同的节点的冗余副本读,所以读数据的时间相应可以非常短,非常适合大数据读取。运行在HDFS上的程序必须是流式访问数据集,接着长时间在大数据集上进行各类分析,所以HDFS的设计旨在提高数据吞吐量,而不是用户交互型的小数据。HDFS放宽了对POSIX(可移植操作系统接口)规范的强制性要求,去掉一些没必要的语义,这样可以获得更好的吞吐量。
4.支持超大文件
由于更高的访问吞吐量,HDFS支持GB级甚至TB级的文件存储,但如果存储大量小文件的话对主节点的内存影响会很大。
5.优化的读取
由于HDFS集群往往是建立在跨多个机架(RACK)的集群机器上的,而同一个机架节点间的网络带宽要优于不同机架上的网络带宽,所以HDFS集群中的读操作往往被转换成离读节点最近的一个节点的数据读取;如果HDFS跨越多个数据中心那么本数据中心的数据复制优先级要高于其他远程数据中心的优先级。
6.数据完整性
从某个数据节点上获取的数据块有可能是损坏的,损坏可能是由于存储设备错误、网络错误或者软件BUG造成的。HDFS客户端软件实现了对HDFS文件内容的校验和检查(checksum),当客户端创建一个新的HDFS文件时,会计算这个文件每个数据块的校验和,并将校验和作为一个单独的隐藏文件保存在同一个HDFS命名空间下。当客户端获取到文件内容后,会对此节点获取的数据与相应文件中的校验和进行匹配。如果不匹配,客户端可以选择从其余节点获取该数据块进行复制。

3.2 HDFS架构

HDFS是一个典型的主从架构,一个主节点或者说是元数据节点(MetadataNode)负责系统命名空间(NameSpace)的管理、客户端文件操作的控制和存储任务的管理分配,多个从节点或者说是数据节点(DataNode)提供真实文件数据的物理支持,系统架构如图3-1所示。

图像说明文字

从图3-1中可看出,客户端可以通过元数据节点从多个数据节点中读取数据块,而这些文件元数据信息的收集是各个数据节点自发提交给元数据节点的,它存储了文件的基本信息。当数据节点的文件信息有变更时,就会把变更的文件信息传送给元数据节点,元数据节点对数据节点的读取操作都是通过这些元数据信息来查找的。这种重要的信息一般会有备份,存储在次级元数据节点(SecondaryMetadataNode)。写文件操作也是需要知道各个节点的元数据信息、哪些块有空闲、空闲块位置、离哪个数据节点最近、备份多少次等,然后再写入。在有至少两个支架的情况下,一般除了写入本支架中的几个节点外还会写入到外部支架节点,这就是所谓的“支架感知”。如图3-1中的Rack1与Rack2支架。

3.2.1数据块

在计算机中,每个磁盘都有自己的物理磁盘块,是读写文件数据的最小单位。对于单机文件系统的块一般由多个物理磁盘块组成,一般磁盘块大小为512 B,文件系统块由几个磁盘块组成达到几千字节,并且系统还有专门的磁盘管理工具(fs和fsck)来管理和维护文件系统,它们直接针对文件系统块操作。
同理,在HDFS上也有块的概念,不过要比单机文件系统大得多,默认为64 MB。在HDFS上的文件被划分成多个64 MB的大块(Chunk)作为独立储存单元。与单机分布式文件系统不同的是,不满一个块大小的数据不会占据整个块空间,也就是这个块空间还可以给其他数据共享。
HDFS设置这么大的块大小是有依据的,目的是把寻址时间 占所有传输数据所用的时间最小化,即增大实际传输数据的时间。假如平均寻址时间为10 ms,磁盘传输速度为100 MB/s,那么为了使寻址时间所占比率达到1%,那么块大小设置为100 MB,很多企业集群设置成128 MB甚至更多,这和磁盘驱动器的传输性能有关。但块大小也不应该设的太大,大了后所占用的数据块数量就少很多,而通常MapReduce会把一个块处理成一个Map任务,Map任务数太小(少于集群节点数量)体现不出并行的优势。
对分布式文件中的块抽象是很好的一种设计,这种设计带来很多好处。如可以存储一个超过集群中任一磁盘容量的大文件,也就是说集群中的节点对分布式文件系统来说是不可见的。此外,通过按块备份可以提高文件系统的容错能力和可靠性,将块冗余备份到其他几个节点上(系统默认共3个),当某个块损坏时就可以从其他节点中读取副本,并且重新冗余备份到其他节点上去,而这个过程是自动完成的,对用户来说是透明的。
Hadoop的脚本命令和UNIX系统一样,都是命令体加命令参数。如HDFS的fsck命令可以显示块信息,检查指定目录的数据块健康状况,具体用法可以参考3.3.4节。
下面命令检查HDFS系统上/input目录下的块信息和文件名,结果如图3-2所示。

图像说明文字

图像说明文字

3.2.2 元数据节点与数据节点

HDFS集群有两种按照主(master)从(slave)模式划分的节点:元数据节点(MetadataNode)和数据节点(DataNode)。
元数据节点负责管理整个集群的命名空间,并且为所有文件和目录维护了一个树状结构的元数据信息,而元数据信息被持久化到本地硬盘上分别对应了两种文件:文件系统镜像文件(FsImage)和编辑日志文件(EditsLog)。文件系统镜像文件存储所有关于命名空间的信息,编辑日志文件存储所有事务的记录。文件系统镜像文件和编辑日志文件是HDFS的核心数据结构,如果这些文件损坏了,整个HDFS实例都将失效,所以需要复制副本,以防止损坏或者丢失。一般会配置两个目录来存储这两个文件,分别是本地磁盘和网络文件系统(NFS),防止元数据节点所在节点磁盘损坏后数据丢失。元数据节点在磁盘上的存储结构如下所示。

图像说明文字

其中,VERSION是一个属性文件,可以通过如下命令查看它所保存的一些版本信息。

图像说明文字

(1)namespaceID:文件系统唯一标识,是HDFS初次格式化的时候生成的。
(2)clusterID:集群ID号,在格式化文件系统之前可以在配置文件里面添加或者在格式化命令里添加。
(3)cTime:表示FsImage创建时间。
(4)storageType:保存数据的类型,这里是元数据结构类型,还有一种是DATA_NODE,表示数据结构类型。
(5)blockpoolID:一个由BlockPoolID标识的blockpool属于一个单一的命名空间,违反了这个规则将会发生错误,并且系统必须检测这个错误以及采取适当的措施。
(6)layoutVersion:是一个负整数,保存了HDFS的持久化在硬盘上的数据结构的格式版本号。目前,HDFS集群中DataNode与MetadataNode都是使用统一的LayoutVersion,所以任何LayoutVersion的改变都会导致DataNode与MetadataNode的升级。
NameNode本质上是一个Jetty服务器 ,提供有关命名空间的配置服务,它包含的元数据信息包括文件的所有者、文件权限、存储文件的块ID和这些块所在的DataNode(DataNode启动后会自动上报)。
当NameNode启动的时候,文件系统镜像文件会被加载到内存,然后对内存里的数据执行记录的操作,以确保内存所保留的数据处于最新的状态。所有对文件系统元数据的访问都是从内存中获取的,而不是文件系统镜像文件。文件系统镜像文件和编辑日志文件只是实现了元数据的持久存储功能,事实上所有基于内存的存储系统大概都是采用这种方式,这样做的好处是加快了元数据的读取和更新操作(直接在内存中进行)。
Hadoop集群包含大量DataNode,DataNode响应客户机的读写请求,还响应MetadataeNode对文件块地创建、删除、移动、复制等命令。DataNode把存储的文件块信息报告给MetadataNode,而这种报文信息采用的心跳机制,每隔一定时间向NameNode报告块映射状态和元数据信息,如果报告在一定时间内没有送达MetadataNode,MetadataNode会认为该节点失联(uncommunicate),长时间没有得到心跳消息直接标识该节点死亡(dead),也就不会再继续监听这个节点,除非该节点恢复后手动联系NameNode。DataNode的文件结构如下:

图像说明文字

Blk_refix:HDFS中的文件数据块,存储的是原始文件内容,最大占134217728 B即128 MB(本系统设置块大小为128 MB)。
Blk_refix.meta:块的元数据文件,包括版本和类型信息的头文件,与一系列块的区域校验和组成,最大占1048583 B,即1 MB。
Subdir:存储的数据还是前面的两种数据。

3.2.3 辅助元数据节点

前面提到文件系统镜像文件会被加载到内存中,然后对内存里的数据执行记录的操作。编辑日志文件会随着事务操作的增加而增大,所以需要把编辑日志文件合并到文件系统镜像文件当中去,这个操作就由辅助元数据节点(Secondary MetadataNode)完成。
辅助元数据节点不是真正意义上的元数据节点,尽管名字很像,但它的主要工作是周期性地把文件系统镜像文件与编辑日志文件合并,然后清空旧的编辑日志文件。由于这种合并操作需要大量CPU消耗和比较多的内存占用,所以往往把其配置在一台独立的节点上。如果没有辅助元数据节点周期性的合并过程,那么每次重启元数据节点会耗费很多时间做合并操作,这种周期性合并过程一方面减少重启时间,另一方面保证了HDFS系统的完整性。但是辅助元数据节点保存的状态要滞后于元数据节点,所以当元数据节点失效后,难免会丢失一部分最新操作数据。辅助元数据节点合并编辑日志文件的过程如图3-3所示,处理流程如下。

图像说明文字

(1)辅助元数据节点发送请求,元数据节点停止把操作信息写进edits文件中,转而新建一个edits.new文件写入。
(2)通过HTTP GE从元数据节点获取旧的编辑日志文件和文件系统镜像文件。
(3)辅助元数据节点加载硬盘上的文件系统镜像文件和编辑日志文件,在内存中合并后成为新的文件系统镜像文件,然后写到磁盘上,这个过程叫作保存点(CheckPoint),合并生成的文件为fsimage.ckpt。
(4)通过HTTP POST将fsimage.ckpt发送回元数据节点。
(5)元数据节点更新文件系统镜像文件,同时把edits.new改名为edits,同时还更新fstime文件来记录保存点执行的时间。
下面为辅助元数据节点的文件组织结构。

图像说明文字

辅助元数据节点的目录设计和元数据节点的目录布局相同,这种设计是为了防止元数据节点发生故障,当没有备份或者NFS也没有的时候,可以通过辅助元数据节点恢复数据。通常采用的方法是用-importCheckpoint选项来重启元数据守护进程(MetadataNode Daemon),当dfs.name.dir没有元数据时,辅助元数据节点可以直接通过定义的fs.checkpoint.dir目录载入最新检查点数据。因此在配置Hadoop的时候,元数据节点目录和辅助元数据节点目录一般分开存储。

3.2.4 安全模式

当元数据节点启动时,会将文件系统镜像载入内存,并执行编辑日志文件中的各项操作,然后开始监听RPC和HTTP请求,此时会进入到一种特殊状态,即安全模式状态(Safe Mode)。在此状态下,各个数据节点发送心跳报告和块列表信息到元数据节点,而块列表信息保存的是数据块的位置信息,元数据节点的内存中会保留所有节点的块列表信息,当块列表信息足够时即退出安全模式,一般30秒钟,所以人们往往会发现刚启动Hadoop集群不能马上进行文件读写操作,但是可以知道文件目录信息(可以访问元数据信息)。但如果元数据节点没有检查到足够多的块列表信息,即不满足配置文件定义的“最小复制条件”(最小副本数为1),那么会把需要的块复制到其他数据节点。实际上这种复制过程会浪费极大的资源,因为只有耐心等待所有数据节点都递交完成块列表信息。
为了查看是否系统处于安全模式,可以使用如下命令:

图像说明文字

如果要进入安全模式,往往在需要维护或者升级系统时候需要让文件系统处于只读状态,可用命令:

图像说明文字

同样离开安全模式使用命令:

图像说明文字

如果要让它在执行某个脚本前先退出安全模式,执行:

图像说明文字

3.2.5 负载均衡

负载均衡,是分布式系统中一个永恒的话题,要让各节点获得分配的任务均衡,发挥各节点的最大效能,不能有的节点任务太多忙不过来,而有的节点任务很少甚至没有任务,这样不但影响完成作业的时间,也极大地浪费了资源。负载均衡也是一个复杂的问题,并不是均衡就等于平均。例如,在分布式文件系统中,共一百个数据块,平均分配到集群中的10个节点,那就是每个节点负责10个数据块,这样就均衡了吗?其实还应该考虑HDFS的机架感知问题。一般来说同一个机架上的节点通信带宽要比不同机架要来的快,而把数据块复制到其他机架上又增加了数据的安全性。另外考虑到属于同一个文件的数据块应该尽量在一个机架上,这样可以减少跨机架的网络带宽。所以具体怎么分配是比较复杂的问题。
在HDFS中,ReplicationTargetChooser类是负责实现为新分配的数据块寻找最优存储位置的。总体说,数据块的分配工作和备份的数量、申请的客户端地址、已注册的数据服务器位置密切相关。其算法基本思路是只考量静态位置信息,优先照顾写入者的速度,让多份备份分配到不同的机架去。此外,HDFS中的Balancer类是为了实现动态的负载调整而存在的。Balancer类派生于Tool类,这说明它是以一个独立的进程存在的,可以独立的运行和配置。它运行有NamenodeProtocol和ClientProtocol两个协议,与主节点进行通信,获取各个数据服务器的负载状况,从而进行调整。主要的调整其实就是一个操作,将一个数据块从一个服务器搬迁到另一个服务器上。Balancer会向相关的目标数据服务器发出一个DataTransferProtocol.OP_REPLACE_BLOCK消息,接收到这个消息的数据服务器,会将数据块写入本地,成功后,通知主节点,删除早先的那个数据服务器上的同一块数据块。
HDFS自带一个均衡器脚本,它启动一个Hadoop的守护进程,执行上述的操作。任何时刻,集群只能有一个均衡器存在,开启一次后会一直运行,直到集群变得均衡,而调整数据块的时候带宽默认为1 Mbit/s,可以通过修改hdfs-site.xml文件中的dfs.balance. bandwidthPerSec属性指定,默认为1048576(单位字节)。
使用负载均衡命令:hadoop balance [-threshold< threshold>]
其中“[ ]”中为可选参数,默认阈值为10%,代表磁盘容量的百分比。

3.2.6 垃圾回收

对分布式文件系统而言,没有利用价值的数据块备份,就是垃圾。在现实生活中,提倡垃圾分类,为了更好地理解分布式文件系统的垃圾收集,实现分类也是很有必要的。基本上,所有的垃圾都可以视为两类,一类是由系统正常逻辑产生的,如某个文件被删除了,所有相关的数据块都沦为了垃圾,或某个数据块被负载均衡器移动了,原始数据块也不幸成了垃圾。此类垃圾最大的特点是主节点是生成垃圾的罪魁祸首,也就是说主节点完全了解有哪些垃圾需要处理。另外还有一类垃圾,是由于系统的一些异常症状产生的,如某个数据服务器停机了一段,重启之后发现其上的某个数据块已经在其他服务器上重新增加了此数据块的备份,它上面的备份因过期而失去了价值,就需要当作垃圾来处理。此类垃圾的特点恰恰相反,即主节点无法直接了解到垃圾状况,这就需要换种方式处理。
在HDFS中,第一类垃圾的判定很容易,在一些正常的逻辑中产生的垃圾,全部被塞进了HDFS的最近无效集(Recent Invalidate Sets)这个Map中,在实际工程中对应于/user/${user}/.Trash/Current这个目录中,如果用户想恢复这个文件,可以检索浏览这个目录并检索该文件。而第二类垃圾的判定,则放在数据服务器发送其数据块信息来的过程中,经过与本地信息的比较,可以断定,此数据服务器上有哪些数据块已经不幸沦为垃圾。同样,这些垃圾也被塞到最近无效集中去。在与数据服务器进行心跳交流的过程中,主节点将会判断哪些数据块需要删除,数据服务器对这些数据块的态度是直接物理删除。在GFS(Google FileSystem)的论文中,对如何删除一个数据块有着不同的理解,它觉着应该先缓存起来,过几天没人想恢复它了再删除。在HDFS的文档中,则明确表示,在现行的应用场景中,没有需要这个需求的地方,因此,直接删除就完了。

3.3 HDFS Shell命令

Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。下面介绍HDFS操作分布式文件系统常用命令。
hdfs URI格式:scheme://authority:path。其中,scheme表示协议名,可以是file或HDFS,前者是本地文件,后者是分布式文件;authority表示集群所在的命名空间;path表示文件或者目录的路径。
如hdfs://localhost:9000/user/trucy/test.txt表示在本机的HDFS系统上的text文本文件目录。假设已经在core-site.xml里配置了fs.default.name=hdfs://localhost:9000,则仅使用/user/trucy/test.txt即可。
HDFS默认工作目录为/user/${USER},${USER}是当前的登录用户名。
注意:本章所用的Hadoop集群环境是独立的高可靠配置的4个节点集群,而不是在虚拟机环境下,所用的命名空间实际配置是:

图像说明文字

如果是按照前面讲Hadoop的安装与配置章节所说的fs.defaultFS应该是hdfs://node:9000,所以此处需要读者按照自己配置方案来解读。

3.3.1 文件处理命令

开启Hadoop的分布式文件系统,键入命令hdfs dfs将输出能够支持的命令的列表,如图3-4所示。

图像说明文字

上面很多命令和Linux命令相似,下面介绍一些常用命令。
(1)hdfs dfs –ls:命令列出指定目录文件和目录。
(2)hdfs dfs –mkdir:创建文件夹。
(3)hdfs dfs –cat/text:查看文件内容。
(4)hdfs dfs –touchz:新建文件。
(5)hdfs dfs –appendToFile < src>< tar>:将src的内容写入tar中。
(6)hdfs dfs –put< src>< tar>:将src的内容写入tar中。
(7)hdfs dfs –rm < src>:删除文件或目录。
(8)hdfs dfs -du < path>:显示占用磁盘空间大小。
HDFS命令列出指定目录文件和目录。
1.hdfs dfs –ls:列出根目录文件和目录
使用方法:hdfs dfs –ls [-d][-h][-R] < paths>
其中:-d:返回paths;-h:按照KMG数据大小单位显示文件大小,如果没有单位,默认为B;-R:级联显示paths下文件,这里paths是个多级目录。
如果是文件,则按照如下格式返回文件信息。
文件名<副本数>文件大小修改日期修改时间权限用户ID,组ID。
如果是目录,则返回它直接子文件的一个列表,就像在UNIX中一样。目录返回列表的信息如下。
目录名< dir>修改日期修改时间权限用户ID,组ID。
示例:列出根目录下的文件或目录。

图像说明文字

结果:

图像说明文字

上述命令也可以这样写:

图像说明文字

列出分布式目录/usr/${USER}下的文件或目录。

图像说明文字

结果:

图像说明文字

当然也可以这样写:hdfs dfs –ls . ,或者直接省略“.”,hdfs dfs –ls。
结果:

图像说明文字

2.mkdir:创建文件夹
使用方法:hdfs dfs -mkdir [-p]< paths>
接受路径指定的URI作为参数,创建这些目录。其行为类似于Linux的mkdir用法,加-p标签标识创建多级目录。
示例:在分布式主目录下(/user/${USER})新建文件夹dir。

图像说明文字

结果:

图像说明文字

在分布式主目录下(/user/${USER})新建文件夹dir0/dir1/dir2/。

图像说明文字

结果:

图像说明文字

3.touch:新建文件
使用方法:hdfs dfs -touchz < path>
当前时间下创建大小为0的空文件,若大小不为0,返回错误信息。
示例:在/user/${USER}/dir下新建文件file。

图像说明文字

结果:

图像说明文字

4.cat、text、tail:查看文件内容
使用方法:hdfs dfs –cat/text [-ignoreCrc] < src>
hdfs dfs –tail [-f] < file>
其中:-ignoreCrc忽略循环检验失败的文件;-f动态更新显示数据,如查看某个不断增长的日志文件。
3个命令都是在命令行窗口查看指定文件内容。区别是text不仅可以查看文本文件,还可以查看压缩文件和Avro序列化的文件,其他两个不可以;tail查看的是最后1 KB的文件(Linux上的tail默认查看最后10行记录)。
示例:在作者的分布式目录下/data/stocks/NYSE下有文件NYSE_daily_prices_Y.csv,用3种方法查看。

图像说明文字

结果:

图像说明文字

5.appendToFile:追写文件
使用方法:hdfs dfs -appendToFile < localsrc> … < dst>
把localsrc指向的本地文件内容写到目标文件dst中,如果目标文件dst不存在,系统自动创建。如果localsrc是“-”,表示数据来自键盘中输入,按“Ctrl+c”组合键结束输入。
示例:在/user/${USER}/dir/file文件中写入文字“hello,HDFS!”

图像说明文字

结果:

图像说明文字

第二种方法,在本地文件系统新建文件localfile并写入文字。

图像说明文字

6.put/get:上传/下载文件
使用方法:hdfs dfs - put [-f] [-p] < localsrc> … < dst>
get [-p] [-ignoreCrc] [-crc] < src> … < localdst>
put把文件从当前文件系统上传到分布式文件系统中,dst为保存的文件名,如果dst是目录,把文件放在该目录下,名字不变。
get把文件从分布式文件系统上复制到本地,如果有多个文件要复制,那么localdst(local destination)即为目录,否则localdst就是要保存在本地的文件名。 其中:-f如果文件在分布式系统上已经存在,则覆盖存储,若不加则会报错;-p保持原始文件的属性(组、拥有者、创建时间、权限等);-ignoreCrc同上。 示例:把上例新建的文件localfile放到分布式文件系统主目录上,保存名为hfile;把hfile下载到本地目录,名字不变。

图像说明文字

除了get方法还可以用copyToLocal,用法一致。
7.Rm:删除文件或目录
使用方法:hdfs dfs -rm [-f] [-r|-R] [-skipTrash] < src> ...
删除指定文件与Linux上的rm命令一致。此外和Linux系统的垃圾回收站一样,HDFS会为每个用户创建一个回收站:/usr/${USER}/.Trash/,通过Shell删除的文件都会在这个目录下存储一个周期,这个周期可以通过配置文件指定。当配置好垃圾回收机制后,元数据节点会开启了一个后台线程Emptier,这个线程专门管理和监控系统回收站下面的所有文件/目录,对于已经超过生命周期的文件/目录,这个线程就会自动的删除它们。当然用户想恢复删除的文件,可以直接操作垃圾回收站目录下的Current目录恢复。
配置垃圾回收需要修改的配置文件:core-site.xml。

图像说明文字

-f如果要删除的文件不存在,不显示提示和错误信息。
-r/R级联删除目录下的所有文件和子目录文件。
-skipTrash直接删除,不进入垃圾回车站。
示例:在分布式主目录下(/user/${USER})删除dir目录以及dir0目录。

图像说明文字

由于没有配置fs.trash.interval,默认为0,即直接删除。
8.du:显示占用磁盘空间大小
使用方法:-du [-s] [-h] < path> …
默认按字节显示指定目录所占空间大小。其中:-s显示指定目录下文件总大小;-h按照KMG数据大小单位显示文件大小,如果没有单位,默认为B。
示例:在分布式主目录下(/user/${USER})新建文件夹dir。

图像说明文字

3.3.2 dfsadmin命令

dfsadmin是一个多任务客户端工具,用来显示HDFS运行状态和管理HDFS,支持的命令如图3-5所示。

图像说明文字

表3-1所示为常用的dfsadmin命令。

图像说明文字

3.3.3 namenode命令

运行namenode进行格式化、升级回滚等操作,支持的命令如图3-6所示。

图像说明文字

表3-2所示为常用的namenode命令。

图像说明文字

3.3.4 fsck命令

fsck命令运行HDFS文件系统检查实用程序,用于和MapReduce作业交互。下面为其命令列表。

图像说明文字

表3-3所示为常用的fsck命令。

图像说明文字

3.3.5 pipes命令

pipes命令运行管道作业,图3-7所示为其所有命令。

图像说明文字

表3-4所示为常用的pipes命令。

图像说明文字

3.3.6 job命令

该命令与Map Reduce作业进行交互和命令,图3-8所示为其所有命令。

图像说明文字

表3-5所示为常用的job命令。

图像说明文字

3.4 HDFS中的Java API的使用

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

图像说明文字

文件在Hadoop中表示一个Path对象,通常封装成一个URI,如HDFS上有个test文件,URI表示成HDFS://TLCluster/data/test。
Hadoop中关于文件操作类基本上全部是在“org.apache.hadoop.fs”包中,这些API能够支持的操作包含打开文件、读写文件、删除文件等。
Hadoop类库中最终面向用户提供的接口类是FileSystem,该类是个抽象类,只能通过来类的get方法得到具体类。get方法存在几个重载版本,常用的是static FileSystem get(Configuration conf);该类封装了几乎所有的文件操作,如mkdir、delete等。综上基本上可以得出操作文件的程序库框架:

图像说明文字

3.4.1 上传文件

通过“FileSystem.copyFromLocalFile(Path src,Patch dst)”可将本地文件上传到HDFS指定的位置上,其中src和dst均为文件的完整路径,具体示例如下。

图像说明文字

结果如图3-9、图3-10、图3-11所示。

图像说明文字

3.4.2 新建文件

通过“FileSystem.create(Path f,Boolean b)”可在HDFS上创建文件,其中f为文件的完整路径,b为判断是否覆盖,具体实现如下。

图像说明文字

结果如图3-12所示。

图像说明文字

3.4.3 查看文件详细信息

通过“Class FileStatus”可查找指定文件在HDFS集群上的具体信息,包括访问时间、修改时间、文件长度、所占块大小、文件拥有者、文件用户组和文件复制数等信息,具体实现如下。

图像说明文字

图像说明文字

运行结果如图3-13所示。

图像说明文字

3.4.4 下载文件

从HDFS下载文件到本地非常简单,直接调用FileSystem. copyToLocalFile( Path src, Path dst)即可。其中src为HDFS上的文件,dst为要下载到本地的文件名,示例如下。

图像说明文字

结果中会出现一个crc文件,里边保存对file文件的循环校验信息,如图3-14所示。

图像说明文字

3.5 RPC通信

RPC(Remote Procedure Call Protocol)即远程调用协议,是一台计算机通过跨越底层网络协议(TCP、UDP等)调用另一台计算机的子程序或者服务所遵守的协议标准。RPC使得分布式网络编程变得简单,程序员不必关心底层协议。如果采用面向对象的编程,那么远程过程调用亦可称作远程调用或远程方法调用,如Hadoop所采用的Java远程方法调用(Java Remote Method Invocation,Java RMI)。RPC的主要特点如下。
(1)透明性:远程调用其他机器上的程序,对用户来说就像是调用本地方法一样。
(2)高性能:RPC server能够并发处理多个来自Client的请求。
(3)可控性:JDK中已经提供了一个RPC框架——RMI,但是该PRC框架过于重量级并且可控之处比较少,所以Hadoop RPC实现了自定义的PRC框架。
Hadoop中的元数据节点与数据节点之间的通信、客户端与元数据节点的通信和数据节点间的通信都是基于RPC机制。总的来说,这种机制的实现需要以下4种技术。
(1)代理模式:RPC机制在Java中的实现其实是遵守软件开发的一个重要设计模式。
(2)反射机制:Java的一个重要特性。
(3)Sequence:Hadoop的序列化技术,Hadoop改写了Java基本数据类型,用于在客户端与服务端数据之间传输简单的二进制流。
(4)NIO:非阻塞IO技术。
Sequence技术会在后面Hadoop IO章中讲到,另外简单介绍一下NIO技术。它是基于反应堆模式(Reactor),或者说是观察者模式(Observer)。以前对端口的访问操作往往在打开一个I/O通道后,read进程将一直等待直到内容全部进来,这会影响程序做其他的事情,改进进程即是让服务端线程监听事件,如果事件发生则会通知服务端,从外界看实现了流畅的I/O读写,也就不阻塞了。下面主要讲解Java的反射机制和代理模式。

3.5.1 反射机制

根据JDK文档说明,Java中的反射机制可以如此定义:Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
Java程序在运行时,Java运行时系统(java runtime system)一直对所有的对象进行所谓的运行时类型标识。这项信息记录了每个对象所属的类。虚拟机通常使用运行时类型信息来选择正确的方法执行,用来保存这些类型信息的类是java.lang.Class类。也就是说,类加载器(ClassLoader)找到了需要调用的类时,就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等信息。以后Java虚拟机要产生该类的实例,就是根据堆内存中存在的该Class类所记载的信息来进行。
Class类中存在以下几个重要的方法。
1.getName()
一个Class对象描述了一个特定类的特定属性,而这个方法就是返回String形式的该类的简要描述。
2.newInstance()
该方法可以根据某个Class对象产生其对应类的实例。需要强调的是,它调用的是此类的默认构造方法。如:

图像说明文字

3.getClassLoader()
返回该Class对象对应的类的类加载器。
4.getComponentType()
该方法针对数组对象的Class对象,可以得到该数组的组成元素所对应对象的Class对象。如:

图像说明文字

而这里得到的class2对象所对应的就应该是int这个基本类型的Class对象。
5.getSuperClass()
返回某子类所对应的直接父类所对应的Class对象。
6.isArray()
判定此Class对象所对应的是否是一个数组对象。
代码示例:

图像说明文字

图像说明文字

执行结果如图3-15 所示。

图像说明文字

3.5.2 代理模式与动态代理

代理模式的作用是为其他对象提供代理,让这个代理来控制对这个对象的访问。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,代理模式类图如图3-16所示。

图像说明文字

在代理模式中的角色。
(1)抽象对象角色(AbstractObject):声明了真实对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
(2)真实对象角色(RealObject):定义了代理对象所代表的目标对象。
(3)代理对象角色(ProxyObject):代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,附加其他操作,相当于对真实对象进行封装,而不是单纯地将调用传递给目标对象。
在实际使用时,一个真实对象角色必须对应一个代理对象角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。所谓动态,就像C语言里面动态分配内存函数malloc一个意思,使用的时候JVM(java virtual machine)才分配资源,即用到前面讲的反射技术。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及以下两个类。
(1)Interface InvocationHandler:该接口中仅定义了一个方法Object,invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类,作用类似于Proxybbject,其中主要包含以下内容。
①Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
②Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
③Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, Invocation Handlerh):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。动态代理类图如图3-17所示。

图像说明文字

示例代码:

图像说明文字

图像说明文字

图3-18所示为运行结果。

图像说明文字

3.5.3 Hadoop RPC 机制与源码分析

RPC源代码在org.apache.hadoop.ipc下,有以下几个主要类。
(1)Client:客户端,连接服务器、传递函数名和相应的参数、等待结果。
(2)Server:服务器端,主要接受Client的请求、执行相应的函数、返回结果。
(3)VersionedProtocol:通信双方所遵循契约的父接口。
(4)RPC:RPC通信机制,主要是为通信的服务方提供代理。
所有涉及协议如图3-19所示。

图像说明文字

下面介绍几个重要的协议。VersionedProtocol是所有RPC协议接口的父接口,其中只有一个方法,即getProtocolVersion()。
1.HDFS相关
ClientDatanodeProtocol:一个客户端和Datanode之间的协议接口,用于数据块恢复。
ClientProtocol:client与Namenode交互的接口,所有控制流的请求均在这里,如创建文件、删除文件等。
DatanodeProtocol:Datanode与Namenode交互的接口,如心跳、blockreport等。
NamenodeProtocol:SecondaryNode与Namenode交互的接口。
2.Mapreduce相关
InterDatanodeProtocol:Datanode内部交互的接口,用来更新block的元数据。
InnerTrackerProtocol:TaskTracker与JobTracker交互的接口,功能与DatanodeProtocol相似。
JobSubmissionProtocol:JobClient与JobTracker交互的接口,用来提交Job、获得Job等与Job相关的操作。
TaskUmbilicalProtocol:Task中子进程与母进程交互的接口,子进程即map、reduce等操作,母进程即TaskTracker,该接口可以回报子进程的运行状态(词汇扫盲:umbilical脐带的,关系亲密的)。
通过对TaskTracker与JobTracker的通信来剖析其通信过程,JobTracker的代理是通过下面的方法得到的。

图像说明文字

它是通过调用RPC类中的静态方法(waitForProxy())而得到了InterTrackerProtocol的一个代理,借助于这个代理对象,TaskTracker就可以与JobTracker进行通信了。

图像说明文字

跟踪Hadoop的源代码,可以发现PRC.waitForProxy()最终是调用的Proxy.NewProxy Instance()来创建一个代理对象,第一个参数是类加载器(代理类在运行的过程中动态生成),第二个参数是要实现的代理类的接口,第三个参数是InvokercationHandler接口的子类,最终调用的也就是InvokercationHandler实现类的invoker()方法。

图像说明文字

从代中可以看到,InvocationHandler的实现类Invoker中主要包含两个成员变量即remoteId(唯一标识RPC的服务器端)、Client(通过工厂模式得到的客户端),invoke()方法中最重要的就是下面的语句:

图像说明文字

其中call方法的第一个参数封装调用方法和参数并实现Writable接口的对象,以便于在分布式环境中传输,第二个参数就用于唯一标识RPC Server,也就是与指定的Server进行通信。call方法的核心代码如下:

图像说明文字

其中会出现一个Call对象,可看到此方法返回的结果是call对象的一个成员变量,也就是说Call封装了Client的请求以及Server的响应,synchronized的使用会同步Client的请求以及Server的响应。通Connection对象的sendParam方法可以将请求发送给Server,那么Connection又是什么呢?

图像说明文字

其实Connection是扩展Thread而得到的一个线程,最终把所有的connection对象都放入一个Hashtable中,同一个ConnectionId的Connection可以复用,降低了创建线程的开销。connection.setupIOstreams()用于在真正的建立连接,并将RPC的header写入到输出流中,通过start方法启动线程,其核心代码如下所示:

图像说明文字

receiveResponse方法主要是从输入流反序列化出value,并将其封装在call对象中,这样client端就得到了server的响应,核心代码如下:

图像说明文字

到此,Hadoop RPC通信机制分析完毕,整个RPC架构如图3-20所示。

图像说明文字

3.6 小结

Hadoop分布式文件系统(HDFS)是一个设计运行在普通硬件设备上的分布式文件系统,具有高容错性,提供高吞吐量,适合于具有大数据集的应用场合。HDFS架构中NameNode维护文件系统命名空间,它也决定着数据块到DataNode的映射,客户端对文件系统的请求(读/写)由DataNode负责处理,在NameNode的指令下,DataNode也负责数据块的创建、删除和复制。HDFS处理文件的命令和Linux上的命令基本是相同的,在掌握HDFS命令的基础上可以更好地了解Linux命令。对于开发方向的人员需要熟练运用HDFS的Java API进行数据操作,并也应该理解Hadoop核心技术之一的RPC通信原理。

目录

  • 第1章 Hadoop概述
  • 第2章 Hadoop安装与配置管理
  • 第3章 HDFS技术
  • 第4章 MapReduce技术
  • 第5章 Hadoop I/O操作
  • 第6章 海量数据库HBase技术
  • 第7章 ZooKeeper技术
  • 第8章 分布式数据仓库技术Hive
  • 第9章 分布式数据分析工具Pig
  • 第10章 Hadoop与RDBMS 数据迁移工具Sqoop
  • 第11章 Hadoop1.x与 Hadoop2.x的比较
  • 第12章 Hadoop实时数据处理技术
  • 附录A 使用Eclipse提交 Hadoop任务相关错误解决
  • 附录B 常用Pig内置函数简介

推荐用户

同系列书

  • Hadoop大数据处理技术基础与实践

    安俊秀 王鹏 靳宇倡

    全书共有12章,从Hadoop起源开始,介绍了Hadoop的安装和配置,并对Hadoop的组件分别进行了介绍,...

    ¥45.00
  • 云计算虚拟化技术与应用

    王培麟 姚幼敏 梁同乐 詹增荣 钟伟成

    全书共11章,分为理论篇、技术篇和实战篇三个部分。本书将虚拟化技术与应用融为一体,较为系统地介绍了虚拟化技术发...

    ¥39.80
  • 云计算技术与应用基础

    刘志成 林东升 彭勇

    本书从云计算技术与应用的8个维度对云计算技术基础进行了全面介绍,内容包括云概述、云标准、云存储、云服务、云桌面...

    ¥45.00
  • 大数据导论 思维、技术与应用

    武志学

    本书将基本概念与实例相结合,由浅入深、循序渐进地对大数据思维、技术和应用做了全面系统的介绍。全书共12章,分为...

    ¥49.80
  • Docker容器技术与应用

    程宁 刘桂兰 丁丽 胡文杰 周永福

    本书以任务为导向,较为全面地介绍了容器技术的相关知识。全书共分为7个项目,包括Docker概述、Docker镜...

    ¥39.80
  • 大数据技术与应用基础

    陈志德 曾燕清 李翔宇

    本书在介绍大数据发展背景、特点及主要技术层面的基础上,对大数据的数据采集、数据存储、常见计算模式和典型系统工具...

    ¥39.80
  • 云计算和大数据技术:概念 应用与实战(第2版)

    王鹏 李俊杰 谢志明 石慧 黄焱

    本书全面介绍云计算与大数据的基础知识、主要技术、基于集群技术的资源整合型云计算技术和基于虚拟化技术的资源切分型...

    ¥35.00
  • 云计算平台管理与应用

    肖伟 郑海清 廖大强

    本书系统地介绍了云计算平台的安装和应用技术。内容包括云计算基础、OpenStack云平台、CloudStack...

    ¥45.00
人邮微信
本地服务
人邮微信
教师服务
二维码
读者服务
读者服务
返回顶部
返回顶部