本章内容
什么是Hadoop
Hadoop项目及其结构
Hadoop的体系结构
Hadoop与分布式开发
Hadoop计算模型—MapReduce
Hadoop的数据管理
小结
1.1.1 Hadoop概述
Hadoop是Apache软件基金会旗下的一个开源分布式计算平台。以Hadoop分布式文件系统HDFS(Hadoop Distributed Filesystem)和MapReduce(Google MapReduce的开源实现)为核心的Hadoop为用户提供了系统底层细节透明的分布式基础架构。HDFS的高容错性、高伸缩性等优点允许用户将Hadoop部署在低廉的硬件上,形成分布式系统;MapReduce分布式编程模型允许用户在不了解分布式系统底层细节的情况下开发并行应用程序。所以用户可以利用Hadoop轻松地组织计算机资源,从而搭建自己的分布式计算平台,并且可以充分利用集群的计算和存储能力,完成海量数据的处理。
1.1.2 Hadoop的历史
Hadoop的源头是Apache Nutch,该项目开始于2002年,是Apache Lucene 的子项目之一。2004年,Google在“操作系统设计与实现”(OSDI,Operating System Design and Implementation)会议上公开发表了题为“MapReduce:Simplified Data Processing on Large Clusters”(MapReduce:简化大规模集群上的数据处理)的论文,之后受到启发的Doug Cutting等人开始尝试实现MapReduce计算框架,并将它与NDFS(Nutch Distributed File System)结合,以支持Nutch引擎的主要算法。由于NDFS和MapReduce在Nutch引擎中有着良好的应用,所以它们于2006年2月被分离出来,成为了一套完整而独立的软件,起名为Hadoop。到了2008年年初,Hadoop已成为 Apache的顶级项目,它被包括Yahoo!在内的很多互联网公司所采用。现在,Hadoop已经发展成为包含HDFS、MapReduce、Pig、ZooKeeper等子项目的集合,用于分布式计算。
1.1.3 Hadoop的功能与作用
我们为什么需要Hadoop呢?众所周知,现代社会的信息量增长速度极快,这些信息里又积累着大量的数据,其中包括个人数据和工业数据。预计到2020年,每年产生的数字信息将会有超过1/3的内容驻留在云平台中或借助云平台处理。我们需要对这些数据进行分析和处理,以获取更多有价值的信息。那么我们如何高效地存储和管理这些数据,如何分析这些数据呢?这时可以选用Hadoop系统,它在处理这类问题时,采用了分布式存储方式,提高了读写速度,并扩大了存储容量。采用MapReduce来整合分布式文件系统上的数据,可保证分析和处理数据的高效。与此同时,Hadoop还采用存储冗余数据的方式保证了数据的安全性。
Hadoop中HDFS的高容错特性,以及它是基于Java语言开发的,这使得Hadoop可以部署在低廉的计算机集群中,同时不限于某个操作系统。Hadoop中HDFS的数据管理能力,MapReduce处理任务时的高效率,以及它的开源特性,使其在同类的分布式系统中大放异彩,并在众多行业和科研领域中被广泛采用。
1.1.4 Hadoop的优势
Hadoop是一个能够让用户轻松架构和使用的分布式计算平台。用户可以轻松地在Hadoop上开发和运行处理海量数据的应用程序。它主要有以下几个优点:
高可靠性:Hadoop按位存储和处理数据的能力值得人们信赖。
高扩展性:Hadoop是在可用的计算机集簇间分配数据并完成计算任务的,这些集簇可以方便地扩展到数以千计的节点中。
高效性:Hadoop能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此其处理速度非常快。
高容错性:Hadoop能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配。
1.1.5 Hadoop的应用现状和发展趋势
由于 Hadoop优势突出,基于Hadoop的应用已经遍地开花,尤其是在互联网领域。Yahoo! 通过集群运行Hadoop,以支持广告系统和Web搜索的研究;Facebook借助集群运行Hadoop,以支持其数据分析和机器学习;百度则使用Hadoop进行搜索日志的分析和网页数据的挖掘工作;淘宝的Hadoop系统用于存储并处理电子商务交易的相关数据;中国移动研究院基于Hadoop的“大云”(BigCloud)系统用于对数据进行分析和并对外提供服务。
2008年2月,Hadoop最大贡献者Yahoo!构建了当时规模最大的Hadoop应用,它们在2000个节点上面执行了超过1万个Hadoop虚拟机器来处理超过5PB的网页内容,分析大约1兆个网络连接之间的网页索引资料。这些网页索引资料压缩后超过300TB。Yahoo!正是基于这些为用户提供了高质量的搜索服务。
Hadoop目前已经取得了非常突出的成绩。随着互联网的发展,新的业务模式还将不断涌现,Hadoop的应用也会从互联网领域向电信、电子商务、银行、生物制药等领域拓展。相信在未来,Hadoop将会在更多的领域中扮演幕后英雄,为我们提供更加快捷优质的服务。
现在Hadoop已经发展成为包含多个子项目的集合。虽然其核心内容是MapReduce和Hadoop分布式文件系统(HDFS),但Hadoop下的Common、Avro、Chukwa、Hive、HBase等子项目也是不可或缺的。它们提供了互补性服务或在核心层上提供了更高层的服务。图1-1展现了Hadoop的项目结构图。
下面将对Hadoop的各个子项目进行更详细的介绍。
1)Core/Common:从Hadoop 0.20版本开始,Hadoop Core项目便更名为Common。Common是为Hadoop其他子项目提供支持的常用工具,它主要包括FileSystem、RPC和串行化库,它们为在廉价的硬件上搭建云计算环境提供基本的服务,并且为运行在该运平台上的软件开发提供了所需的API。
2)Avro:Avro是用于数据序列化的系统。它提供了丰富的数据结构类型、快速可压缩的二进制数据格式、存储持久性数据的文件集、远程调用RPC的功能和简单的动态语言集成功能。其中,代码生成器既不需要读写文件数据,也不需要使用或实现RPC协议,它只是一个可选的对静态类型语言的实现。
Avro系统依赖于模式(Schema),Avro数据的读和写是在模式之下完成的。这样就可以减少写入数据的开销,提高序列化的速度并缩减其大小。同时,也可以方便动态脚本语言的使用,因为数据连同其模式都是自描述的。
在RPC中,Avro系统的客户端和服务端通过握手协议进行模式的交换。因此当客户端和服务端拥有彼此全部的模式时,不同模式下的相同命名字段、丢失字段和附加字段等信息的一致性问题就得到了很好的解决。
3)MapReduce:MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。“映射”(map)、“化简”(reduce)等概念和它们的主要思想都是从函数式编程语言中借来的。它使得编程人员在不了解分布式并行编程的情况下也能方便地将自己的程序运行在分布式系统上。MapReduce在执行时先指定一个map(映射)函数,把输入键值对映射成一组新的键值对,经过一定的处理后交给reduce,reduce对相同key下的所有value进行处理后再输出键值对作为最终的结果。
图1-2是MapReduce的任务处理流程图,它展示了MapReduce程序将输入划分到不同的map上,再将map的结果合并到reduce,然后进行处理的输出过程。详细介绍请参考本章的1.3节。
4)HDFS:是一个分布式文件系统。由于HDFS具有高容错性(fault-tolerant)的特点,所以可以设计部署在低廉(low-cost)的硬件上。它可以通过提供高吞吐率(high throughput)来访问应用程序的数据,适合那些有着超大数据集的应用程序。HDFS放宽了可移植操作系统接口(POSIX,Portable Operating System Interface)的要求,这样就可以实现以流的形式访问文件系统中的数据。HDFS原本是开源的Apache项目Nutch的基础结构,最后它成为了Hadoop的基础架构之一。
以下是HDFS的设计目标:
检测和快速恢复硬件故障。硬件故障是常见的问题,整个HDFS系统由数百台或数千台存储着数据文件的服务器组成,而如此多的服务器意味着高故障率,因此,故障的检测和自动快速恢复是HDFS的一个核心目标。
流式的数据访问。HDFS使应用程序能流式地访问它们的数据集。HDFS被设计成适合进行批量处理,而不是用户交互式的处理。所以它重视数据吞吐量,而不是数据访问的反应速度。
简化一致性模型。大部分的HDFS程序操作文件时需要一次写入,多次读取。一个文件一旦经过创建、写入、关闭之后就不需要修改了,从而简化了数据一致性问题和高吞吐量的数据访问问题。
通信协议。所有的通信协议都在TCP/IP协议之上。一个客户端和明确配置了端口的名字节点(NameNode)建立连接之后,它和名称节点(NameNode)的协议便是客户端协议(Client Protocal)。数据节点(DataNode)和名字节点(NameNode)之间则用数据节点协议(DataNode Protocal)。
关于HDFS的具体介绍请参考本章的1.3节。
5)Chukwa:Chukwa是开源的数据收集系统,用于监控和分析大型分布式系统的数据。Chukwa是在Hadoop的HDFS和MapReduce框架之上搭建的,它同时继承了Hadoop的可扩展性和健壮性。Chukwa通过HDFS来存储数据,并依赖于MapReduce任务处理数据。Chukwa中也附带了灵活且强大的工具,用于显示、监视和分析数据结果,以便更好地利用所收集的数据。
6)Hive:Hive最早是由Facebook设计的,是一个建立在Hadoop基础之上的数据仓库,它提供了一些用于数据整理、特殊查询和分析存储在Hadoop文件中的数据集的工具。Hive提供的是一种结构化数据的机制,它支持类似于传统RDBMS中的SQL语言来帮助那些熟悉SQL的用户查询Hadoop中的数据,该查询语言称为Hive QL。与此同时,那些传统的MapReduce编程人员也可以在Mapper或Reducer中通过Hive QL查询数据。Hive编译器会把Hive QL编译成一组MapReduce任务,从而方便MapReduce编程人员进行Hadoop应用的开发。
7)HBase:HBase是一个分布式的、面向列的开源数据库,该技术来源于Google的论文“Bigtable:一个结构化数据的分布式存储系统”。如同Bigtable利用了Google文件系统(Google File System)提供的分布式数据存储方式一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Hadoop项目的子项目。HBase不同于一般的关系数据库,其一,HBase是一个适合于存储非结构化数据的数据库;其二,HBase是基于列而不是基于行的模式。HBase和Bigtable使用相同的数据模型。用户将数据存储在一个表里,一个数据行拥有一个可选择的键和任意数量的列。由于HBase表示疏松的,用户可以给行定义各种不同的列。HBase主要用于需要随机访问、实时读写的大数据(Big Data)。具体介绍请参考本书第12章“HBase详解”。
8)Pig:Pig是一个对大型数据集进行分析和评估的平台。Pig最突出的优势是它的结构能够经受住高度并行化的检验,这个特性让它能够处理大型的数据集。目前,Pig的底层由一个编译器组成,它在运行的时候会产生一些MapReduce程序序列,Pig的语言层由一种叫做Pig Latin的正文型语言组成。有关Pig的具体内容请参考本书第14章“Pig详解”。
上面讨论的8个子项目在本书中都有相应的章节进行详细的介绍。
如前面的内容所说,HDFS和MapReduce是Hadoop的两大核心。而整个Hadoop的体系结构主要是通过HDFS来实现对分布式存储的底层支持的,并且它会通过MapReduce来实现对分布式并行任务处理的程序支持。
1.3.1 HDFS的体系结构
我们首先介绍HDFS的体系结构,HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群是由一个NameNode和若干个DataNode组成的。其中NameNode作为主服务器,管理文件系统的命名空间和客户端对文件的访问操作;集群中的DataNode管理存储的数据。HDFS允许用户以文件的形式存储数据。从内部来看,文件被分成若干个数据块,而且这若干个数据块存放在一组DataNode上。NameNode执行文件系统的命名空间操作,比如打开、关闭、重命名文件或目录等,它也负责数据块到具体DataNode的映射。DataNode负责处理文件系统客户端的文件读写请求,并在NameNode的统一调度下进行数据块的创建、删除和复制工作。图1-3给出了HDFS的体系结构。
NameNode和DataNode都被设计成可以在普通商用计算机上运行。这些计算机通常运行的是GNU/Linux操作系统。HDFS采用Java语言开发,因此任何支持Java的机器都可以部署NameNode和DataNode。一个典型的部署场景是集群中的一台机器运行一个NameNode实例,其他机器分别运行一个DataNode实例。当然,并不排除一台机器运行多个DataNode实例的情况。集群中单一的NameNode的设计则大大简化了系统的架构。NameNode是所有HDFS元数据的管理者,用户数据永远不会经过NameNode。
1.3.2 MapReduce的体系结构
接下来介绍MapReduce的体系结构,MapReduce是一种并行编程模式,这种模式使得软件开发者可以轻松地编写出分布式并行程序。在Hadoop的体系结构中,MapReduce是一个简单易用的软件框架,基于它可以将任务分发到由上千台商用机器组成的集群上,并以一种高容错的方式并行处理大量的数据集,实现Hadoop的并行任务处理功能。MapReduce框架是由一个单独运行在主节点上的JobTracker和运行在每个集群从节点上的TaskTracker共同组成的。主节点负责调度构成一个作业的所有任务,这些任务分布在不同的从节点上。主节点监控它们的执行情况,并且重新执行之前失败的任务;从节点仅负责由主节点指派的任务。当一个Job被提交时,JobTracker接收到提交作业和配置信息之后,就会将配置信息等分发给从节点,同时调度任务并监控TaskTracker的执行。
从上面的介绍可以看出,HDFS和MapReduce共同组成了Hadoop分布式系统体系结构的核心。HDFS在集群上实现了分布式文件系统,MapReduce在集群上实现了分布式计算和任务处理。HDFS在MapReduce任务处理过程中提供了文件操作和存储等支持,MapReduce在HDFS的基础上实现了任务的分发、跟踪、执行等工作,并收集结果,二者相互作用,完成了Hadoop分布式集群的主要任务。
我们通常说的分布式系统其实是分布式软件系统,即支持分布式处理的软件系统,它是在通信网络互联的多处理机体系结构上执行任务的,包括分布式操作系统、分布式程序设计语言及其编译(解释)系统、分布式文件系统和分布式数据库系统等。Hadoop是分布式软件系统中文件系统这一层的软件,它实现了分布式文件系统和部分分布式数据库的功能。Hadoop中的分布式文件系统HDFS能够实现数据在计算机集群组成的云上高效的存储和管理,Hadoop中的并行编程框架MapReduce能够让用户编写的Hadoop并行应用程序运行更加简化。下面简单介绍一下基于Hadoop进行分布式并发编程的相关知识,详细的介绍请参看后面有关MapReduce编程的章节。
Hadoop上的并行应用程序开发是基于MapReduce编程框架的。MapReduce编程模型的原理是:利用一个输入的key/value 对集合来产生一个输出的key/value 对集合。MapReduce库的用户用两个函数来表达这个计算:Map和Reduce。
用户自定义的map函数接收一个输入的key/value 对,然后产生一个中间key/value 对的集合。MapReduce把所有具有相同key值的value集合在一起,然后传递给reduce函数。
用户自定义的reduce函数接收key和相关的value集合。reduce函数合并这些value值,形成一个较小的value集合。一般来说,每次reduce函数调用只产生0或1个输出的value值。通常我们通过一个迭代器把中间的value值提供给reduce 函数,这样就可以处理无法全部放入内存中的大量的value值集合了。
图1-4是MapReduce的数据流图,这个过程简而言之就是将大数据集分解为成百上千个小数据集,每个(或若干个)数据集分别由集群中的一个节点(一般就是一台普通的计算机)进行处理并生成中间结果,然后这些中间结果又由大量的节点合并,形成最终结果。图1-4也指出了MapReduce框架下并行程序中的三个主要函数:map、reduce、main。在这个结构中,需要用户完成的工作仅仅是根据任务编写map和reduce两个函数。
MapReduce计算模型非常适合在大量计算机组成的大规模集群上并行运行。图1-4中的每一个 map 任务和每一个reduce 任务均可以同时运行于一个单独的计算节点上,可想而知,其运算效率是很高的,那么这样的并行计算是如何做到的呢?下面将简单介绍一下其原理。
1.数据分布存储
Hadoop分布式文件系统(HDFS)由一个名称节点(NameNode )和N个数据节点 (DataNode)组成,每个节点均是一台普通的计算机。在使用方式上HDFS与我们熟悉的单机文件系统非常类似,它可以创建目录,创建、复制和删除文件,以及查看文件的内容等。但HDFS底层把文件切割成了Block,然后这些 Block 分散地存储于不同的 DataNode 上,每个 Block 还可以复制数份数据存储于不同的 DataNode 上,达到容错容灾的目的。NameNode则是整个 HDFS 的核心,它通过维护一些数据结构来记录每一个文件被切割成了多少个 Block、这些 Block 可以从哪些 DataNode 中获得,以及各个 DataNode 的状态等重要信息。
2. 分布式并行计算
Hadoop 中有一个作为主控的 JobTracker,用于调度和管理其他的 TaskTracker,JobTracker 可以运行于集群中的任意一台计算机上。TaskTracker则负责执行任务,它必须运行于 DataNode 上,也就是说DataNode 既是数据存储节点,也是计算节点。 JobTracker 将 map 任务和 reduce 任务分发给空闲的 TaskTracker,让这些任务并行运行,并负责监控任务的运行情况。如果某一个 TaskTracker 出了故障,JobTracker 会将其负责的任务转交给另一个空闲的 TaskTracker 重新运行。
3. 本地计算
数据存储在哪一台计算机上,就由哪台计算机进行这部分数据的计算,这样可以减少数据在网络上的传输,降低对网络带宽的需求。在 Hadoop 这类基于集群的分布式并行系统中,计算节点可以很方便地扩充,它所能够提供的计算能力近乎无限,但是由于数据需要在不同的计算机之间流动,故网络带宽变成了瓶颈,“本地计算”是一种最有效的节约网络带宽的手段,业界把这形容为“移动计算比移动数据更经济”。
4. 任务粒度
把原始大数据集切割成小数据集时,通常让小数据集小于或等于 HDFS 中一个 Block 的大小(默认是64MB),这样能够保证一个小数据集是位于一台计算机上的,便于本地计算。有 M 个小数据集待处理,就启动 M 个 map 任务,注意这 M 个map 任务分布于 N 台计算机上,它们会并行运行,reduce 任务的数量 R 则可由用户指定。
5. 数据分割(Partition)
把 map 任务输出的中间结果按 key 的范围划分成R份(R是预先定义的reduce 任务的个数),划分时通常使用 hash 函数(如:hash(key) mod R),这样可以保证某一范围内的 key一定是由一个 reduce 任务来处理的,可以简化 Reduce 的过程。
6. 数据合并(Combine)
在数据分割之前,还可以先对中间结果进行数据合并(Combine),即将中间结果中有相同 key的 <key, value> 对合并成一对。Combine 的过程与reduce 的过程类似,很多情况下可以直接使用reduce 函数,但 Combine 是作为map 任务的一部分,在执行完map函数后紧接着执行的。Combine 能够减少中间结果中 <key, value> 对的数目,从而降低网络流量。
7. Reduce
Map 任务的中间结果在做完 Combine 和 Partition 之后,以文件形式存于本地磁盘上。中间结果文件的位置会通知主控 JobTracker,JobTracker 再通知 reduce 任务到哪一个 DataNode 上去取中间结果。注意,所有的map 任务产生的中间结果均按其key 值用同一个 hash 函数划分成了R份,R个reduce 任务各自负责一段key 区间。每个reduce 需要向许多个map 任务节点取得落在其负责的key 区间内的中间结果,然后执行reduce函数,形成一个最终的结果文件。
8. 任务管道
有 R 个 reduce 任务,就会有 R 个最终结果,很多情况下这 R 个最终结果并不需要合并成一个最终结果,因为这 R 个最终结果又可以作为另一个计算任务的输入,开始另一个并行计算任务,这也就形成了任务管道。
这里简要介绍了在并行编程方面Hadoop中MapReduce编程模型的原理、流程、程序结构和并行计算的实现,MapReduce程序的详细流程、编程接口、程序实例等请参见后面章节。
MapReduce是Google公司的核心计算模型,它将运行于大规模集群上的复杂的并行计算过程高度地抽象为了两个函数:map和reduce。Hadoop是Doug Cutting受到Google发表的关于MapReduce的论文的启发而开发出来的。Hadoop中的MapReduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千台商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上T级别的数据集,实现了Hadoop在集群上的数据和任务的并行计算与处理。
一个MapReduce 作业(job) 通常会把输入的数据集切分为若干个独立的数据块,由 map任务(task)以完全并行的方式处理它们。框架会先对map的输出进行排序,然后把结果输入给reduce任务。通常作业的输入和输出都会被存储在文件系统中。整个框架负责任务的调度和监控,以及重新执行已经失败的任务。
通常,MapReduce框架和分布式文件系统是运行在一组相同的节点上的,也就是说,计算节点和存储节点在一起。这种配置允许框架在那些已经存好数据的节点上高效地调度任务,这可以使整个集群的网络带宽被非常高效的利用。
MapReduce框架由一个单独的master JobTracker 和集群节点上的slave TaskTracker共同组成。master负责调度构成一个作业的所有任务,这些任务分布在不同的slave上。master监控它们的执行情况,并重新执行已经失败的任务,而slave仅负责执行由master指派的任务。
在Hadoop上运行的作业需要指明程序的输入/输出位置(路径),并通过实现合适的接口或抽象类来提供map和reduce函数。同时还需要指定作业的其他参数,构成作业配置(job configuration)。在Hadoop的 jobclient提交作业(jar包/可执行程序等)和配置信息给JobTracker之后,JobTracker会负责分发这些软件和配置信息给slave及调度任务,并监控它们的执行,同时提供状态和诊断信息给jobclient。
前面重点介绍了Hadoop及其体系结构和计算模型MapReduce,现在开始介绍Hadoop的数据管理,主要包括Hadoop的分布式文件系统HDFS、分布式数据库HBase和数据仓库工具Hive的数据管理。
1.6.1 HDFS的数据管理
HDFS是分布式计算的存储基石,Hadoop分布式文件系统和其他分布式文件系统有很多类似的特质:
对于整个集群有单一的命名空间;
具有数据一致性。适合一次写入多次读取的模型,客户端在文件没有被成功创建之前是无法看到文件存在的;
文件会被分割成多个文件块,每个文件块被分配存储到数据节点上,而且会根据配置由复制文件块来保证数据的安全性。
从前面的介绍和图1-3可以看出,HDFS通过三个重要的角色来进行文件系统的管理:NameNode、DataNode和Client。NameNode可以看做是分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等。NameNode会将文件系统的 Metadata存储在内存中,这些信息主要包括文件信息、每一个文件对应的文件块的信息和每一个文件块在DataNode中的信息等。 DataNode是文件存储的基本单元,它将文件块(Block)存储在本地文件系统中,保存了所有Block的Metadata,同时周期性地将所有存在的 Block信息发送给NameNode。Client就是需要获取分布式文件系统文件的应用程序。以下通过三个具体的操作来说明HDFS对数据的管理。
(1)文件写入
1) Client向NameNode发起文件写入的请求。
2)NameNode根据文件大小和文件块的配置情况,返回给Client它所管理的DataNode的信息。
3)Client将文件划分为多个Block,根据DataNode的地址信息,按顺序将其写入每一个DataNode块中。
(2)文件读取
1) Client向NameNode发起读取文件的请求。
2) NameNode返回文件存储的DataNode信息。
3)Client读取文件信息。
(3)文件块(Block)复制
1) NameNode发现部分文件的Block不符合最小复制数这一要求或部分DataNode失效。
2)通知DataNode相互复制Block。
3)DataNode开始直接相互复制。
HDFS作为分布式文件系统在数据管理方面还有几个值得借鉴的功能:
文件块(Block)的放置:一个Block会有三份备份,一份放在NameNode指定的DataNode上,另一份放在与指定的DataNode不在同一台机器上的DataNode上,最后一份放在与指定的DataNode在同一Rack上的DataNode上。备份的目的是为了数据安全,采用这种配置方式主要是考虑同一Rack失败的情况,以及不同Rack之间的数据拷贝会带来的性能问题。
心跳检测:用心跳检测DataNode的健康状况,如果发现问题就采取数据备份的方式来保证数据的安全性。
数据复制(场景为DataNode失败、需要平衡DataNode的存储利用率和平衡DataNode数据交互压力等情况):使用Hadoop时可以用HDFS的balancer命令配置Threshold来平衡每一个DataNode的磁盘利用率。假设设置了Threshold为10%,那么执行balancer命令的时候,首先会统计所有DataNode的磁盘利用率的平均值,然后判断如果某一个DataNode的磁盘利用率超过这个均值,那么将会把这个DataNode的block转移到磁盘利用率低的DataNode上,这对于新节点的加入来说十分有用。
数据校验:采用CRC32做数据校验。在写入文件Block的时候,除了写入数据外还会写入校验信息,在读取的时候则需要校验后再读入。
单个NameNode:如果失败,任务处理信息将会记录在本地文件系统和远端的文件系统中。
数据管道性的写入:当客户端要写入文件到DataNode上时,客户端首先会读取一个Block,然后写到第一个DataNode上,接着由第一个 DataNode将其传递到备份的DataNode上,直到所有需要写入这个Block的DataNode都成功写入后,客户端才会开始写下一个 Block。
安全模式:分布式文件系统启动的时候会有安全模式(系统运行期间也可以通过命令进入安全模式),当分布式文件系统处于安全模式时,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。安全模式主要是为了在系统启动的时候检查各个DataNode上的数据块的有效性,同时根据策略进行必要的复制或删除部分数据块。在实际操作过程中,若在系统启动时修改和删除文件会出现安全模式不允许修改的错误提示,只需要等待一会儿即可。
1.6.2 HBase的数据管理
HBase是一个类似Bigtable的分布式数据库,它的大部分特性和Bigtable一样,是一个稀疏的、长期存储的(存在硬盘上)、多维度的排序映射表。这张表的索引是行关键字、列关键字和时间戳。每个值是一个不解释的字符数组,数据都是字符串,没有类型。用户在表格中存储数据,每一行都有一个可排序的主键和任意多的列。由于是稀疏存储的,所以同一张表里面的每一行数据都可以有截然不同的列。列名字的格式是“<family>:<label>”,它是由字符串组成的,每一张表有一个family集合,这个集合是固定不变的,相当于表的结构,只能通过改变表结构来改变表的family集合,但是label值相对于每一行来说都是可以改变的。
HBase把同一个family中的数据存储在同一个目录下,而HBase的写操作是锁行的,每一行都是一个原子元素,都可以加锁。所有数据库的更新都有一个时间戳标记,每次更新都会生成一个新的版本,而HBase会保留一定数量的版本,这个值是可以设定的。客户端可以选择获取距离某个时间点最近的版本,或者一次获取所有版本。
以上从微观上介绍了HBase的一些数据管理措施。那么HBase作为分布式数据库在整体上从集群出发又是如何管理数据的呢?
HBase在分布式集群上主要依靠由HRegion、HMaster、HClient组成的体系结构从整体上管理数据。
HBase体系结构的三大重要组成部分是:
HBaseMaster:HBase主服务器,与Bigtable的主服务器类似。
HRegionServer:HBase域服务器,与Bigtable的Tablet服务器类似。
HBaseClient:HBase客户端是由org.apache.hadoop.HBase.client.HTable定义的。
下面将对这三个组件进行详细的介绍。
(1)HBaseMaster
一个HBase只部署一台主服务器,它通过领导选举算法(Leader Election Algorithm)确保只有唯一的主服务器是活跃的,ZooKeeper保存主服务器的服务器地址信息。如果主服务器瘫痪,可以通过领导选举算法从备用服务器中选择新的主服务器。
主服务器初始化集群。当主服务器第一次启动时,会试图从HDFS获取根或根域目录,若获取失败则创建根或根域目录,以及第一个元域目录。下次启动时,主服务器就可以获取集群和集群中所有域的信息了。
主服务器负责域的分配工作。首先,主服务器会分配根域,并存储指向根域所在域服务器地址的指针。其次,主服务器遍历根域查询元域,并分配元域到域服务器中。每个元域中包含了所有的用户域,用户域中存储了多个用户表。如果所有的元域分配完毕,主服务器将会分配用户域到相应的域服务器,以保持域服务器间的负载平衡。
主服务器时刻监视着域服务器的运行状态。一旦主服务器检测到某一域服务器不可达时,它将分离出域服务器上的每个域的预写日志(write-ahead log)文件。之后,主服务器会将域重新分配到其他域服务器上,并运行之。如果主服务器发现一个域服务器超负荷运行,则会取消或关闭该域服务器的一些域,并将这些域分配到其他低负载的域服务器上。
主服务器还负责表格的管理。例如,调整表格的在线/离线状态和改变表格的模式(增加或删除列族)等。此外,客户端还可以请求本地域直接从域服务器上读取数据。
在Bigtable中,当主服务器和域服务器的连接断开时,域服务器仍然可以继续服务,因为Bigtable提供了一种额外的锁管理机制,这种机制中的锁管理器(Chubby)保证了域服务器服务的可用性。而在HBase中,由于没有提供锁管理机制,当主服务器崩溃时,整个集群系统都要重新启动,因为主服务器是所有域服务器的管理中心。
下面介绍元表和根表的概念:
元表(Meta Table)包含了所有用户域的基本信息,域信息包括起始关键字、结束关键字、域是否在线、域所在的域服务器地址等。元表会随着用户域的增长而增长。
根表(Root Table)被定义为存储单一域的信息,并指向元表中的所有域。与元表一样,根表也包含每个元域的信息和元域所在的域服务器地址。
根表和元表中的每行大约为1KB。域默认大小为256MB,根域可以映射2.6×105个元域。同样,元域可以映射相应数量的用户域。因此,根域可以映射6.9×1010个用户域,大约可以存储1.9×1019字节的数据。
(2)HRegionServer
HBase域服务器主要有服务于主服务器分配的域、处理客户端的读写请求、缓冲区回写、压缩和分割域等功能。
每个域只能由一台域服务器来服务。当它开始服务于某域时,它会从HDFS文件系统中读取该域的日志和所有存储文件。同时它还会管理操作HDFS文件的持久性存储工作。
客户端通过与主服务器通信获取域和域所在域服务器的列表信息后,就可以直接向域服务器发送域读写请求了。域服务器收到写请求时,首先将写请求信息写入一个预写日志文件中,该文件取名为HLog。同一个域的所有写请求都被记录在同一个HLog文件中。一旦写请求被记录在HLog中之后,它将被缓存在存储缓存区(MemCache)中。每个HStore对应一个存储缓存区。对于读请求,域服务器先要检测请求数据在存储缓存区中是否被命中,如果没有命中,域服务器再去查找相关的映射文件。
当存储缓存区的大小达到一定阈值后,需要将存储缓存区中的数据回写到磁盘上,形成映射文件,并在HLog日志文件中标记。因此当再次执行时,可以跳跃到最后一次回写之前的操作上。回写也可能因域服务器存储器压力而被触发。
当映射文件的数量达到一定阈值时,域服务器会将最近常写入的映射文件进行轻度的合并压缩。此外,域服务器还会周期性地对所有的映射文件进行压缩,使其成为单一的映射文件。之所以周期性地压缩所有的映射文件,是因为最早的映射文件通常都比较大,而最近的映射文件则要小很多,压缩要消耗很多的时间,具体消耗的时间主要取决于读取、合并和写出最大映射文件所需要的I/O操作次数。压缩和处理读写请求是同时进行的。在一个新的映射文件移入之前,读写操作将被挂起,直到映射文件被加入HStore的活跃映射文件列表中,且已合并的旧映射文件被删除后,才会释放读写操作。
当HStore中映射文件的大小达到一定的阈值时(目前默认的阈值为256MB),域服务器就要对域进行分割了。域被均分为两个子域,分割操作执行速度很快,因为子域是直接从父域中读取数据的。之后,父域处于离线状态。域服务器在元域中记录新的子域,并通知主服务器可以将子域分配给其他域服务器。如果域分割消息在网络传输中丢失,主服务器可以在周期性扫描元域中未被分配的域信息时发现分割操作。一旦父域被关闭,所有对父域的读写操作将被挂起。客户端则会探测域的分割信息,当新的子域在线时,客户端再发出读写请求。当子域触发压缩操作时,父域的数据将复制到子域中。父域将会在两个子域都完成压缩操作时被回收。
(3)HBaseClient
HBase客户端负责查找用户域所在的域服务器地址。HBase客户端会与HBase主机交换消息以查找根域的位置,这是两者之间唯一的交流。
定位根域后,客户端连接根域所在的域服务器,并扫描根域获取元域信息,元域包含所需用户域的域服务器地址。客户端再连接元域所在的域服务器,扫描元域来获取所需用户域所在的域服务器地址。定位用户域后,客户端连接用户域所在的域服务器并发出读写请求。用户域的地址将在客户端中被缓存,后续的请求无须重复上述过程。
不管是由于主服务器为了负载均衡而重新分配域还是域服务器崩溃,客户端都会重新扫描元表来定位新的用户域地址。如果元域被重新分配,客户端将扫描根域来定位新的元域地址。如果根域也被重新分配,客户端将会连接主机定位新的根域地址,并通过重复上述过程来定位用户域地址。
综上所述,在HBase的体系结构中,HBase主要由主服务器、域服务器和客户端三部分组成。主服务器作为HBase的中心,管理着整个集群中的所有域,监控每个域服务器的运行情况等;域服务器接收来自服务器的分配域,处理客户端的域读写请求并回写映射文件等;客户端主要用来查找用户域所在的域服务器地址信息。
1.6.3 Hive的数据管理
Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,用来进行数据提取、转化、加载,这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive定义了简单的类 SQL 查询语言,称为 QL,它允许熟悉 SQL 的用户查询数据。作为一个数据仓库,Hive的数据管理按照使用层次可以从元数据存储、数据存储和数据交换三个方面来介绍。
(1)元数据存储
Hive 将元数据存储在 RDBMS 中,有三种模式可以连接到数据库:
Single User Mode:此模式连接到一个 In-memory 的数据库 Derby,一般用于 Unit Test。
Multi User Mode:通过网络连接到一个数据库中,这是最常用的模式。
Remote Server Mode:用于非 Java 客户端访问元数据库,在服务器端启动一个 MetaStoreServer,客户端则利用 Thrift 协议通过 MetaStoreServer来访问元数据库。
(2)数据存储
首先,Hive 没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由地组织 Hive 中的表,只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,它就可以解析数据了。
其次,Hive 中所有的数据都存储在 HDFS 中,Hive 中包含4种数据模型:Table、External Table、Partition、Bucket。
Hive 中的 Table 和数据库中的 Table 在概念上是类似的,每一个 Table 在 Hive 中都有一个相应的目录来存储数据。例如,一个表 pvs,它在 HDFS 中的路径为:/wh/pvs,其中,wh 是在 hive-site.xml 中由 ${hive.metastore.warehouse.dir} 指定的数据仓库的目录,所有的 Table 数据(不包括 External Table)都保存在这个目录中。
Partition 对应于数据库中Partition 列的密集索引,但是 Hive 中 Partition 的组织方式与数据库中的很不相同。在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 数据都存储在对应的目录中。例如:pvs 表中包含 ds 和 city 两个 Partition,则对应于 ds = 20090801, city = US 的 HDFS 子目录为:/wh/pvs/ds=20090801/city=US;对应于 ds = 20090801, city = CA 的 HDFS 子目录为:/wh/pvs/ds=20090801/city=CA。
Buckets 对指定列计算 hash,根据 hash 值切分数据,目的是为了便于并行,每一个 Buckets对应一个文件。将 user 列分散至 32 个Bucket上,首先对 user 列的值计算 hash,比如,对应 hash 值为 0 的 HDFS 目录为:/wh/pvs/ds=20090801/city=US/part-00000;对应hash 值为 20 的 HDFS 目录为:/wh/pvs/ds=20090801/city=US/part-00020。
External Table 指向已经在 HDFS 中存在的数据,可以创建 Partition。它和 Table 在元数据的组织结构上是相同的,而在实际数据的存储上则有较大的差异。
在Table 的创建过程和数据加载过程(这两个过程可以在同一个语句中完成)中,实际数据会被移动到数据仓库目录中。之后对数据的访问将会直接在数据仓库的目录中完成。删除表时,表中的数据和元数据将会被同时删除。
External Table 只有一个过程,因为加载数据和创建表是同时完成的。实际数据是存储在 Location 后面指定的 HDFS 路径中的,它并不会移动到数据仓库目录中。
(3)数据交换
数据交换主要分为以下几个部分(如图1-5所示):
用户接口:包括客户端、Web界面和数据库接口。
元数据存储:通常是存储在关系数据库中的,如MySQL、Derby等。
解释器、编译器、优化器、执行器。
Hadoop:用 HDFS进行存储,利用 MapReduce 进行计算。
用户接口主要有三个:客户端、数据库接口和Web界面,其中最常用的是客户端。Client 是 Hive 的客户端,当启动 Client 模式时,用户会想要连接Hive Server,这时需要指出 Hive Server 所在的节点,并且在该节点启动 Hive Server。Web界面是通过浏览器访问 Hive的。
Hive 将元数据存储在数据库中,如 MySQL、Derby中。Hive 中的元数据包括表的名字、表的列和分区及其属性、表的属性(是否为外部表等)、表数据所在的目录等。
解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化到查询计划的生成。生成的查询计划存储在 HDFS 中,并在随后由 MapReduce调用执行。
Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成(包含 * 的查询不会生成 MapRedcue 任务,比如 select * from tbl)。
以上从Hadoop的分布式文件系统HDFS、分布式数据库HBase和数据仓库工具Hive入手介绍了Hadoop的数据管理,它们都通过自己的数据定义、体系结构实现了数据从宏观到微观的立体化管理,完成了Hadoop平台上大规模的数据存储和任务处理。
本章首先介绍了Hadoop分布式计算平台:它是由Apache软件基金会开发的一个开源分布式计算平台。以Hadoop分布式文件系统(HDFS)和MapReduce为核心的Hadoop为用户提供了系统底层细节透明的分布式基础架构。由于Hadoop拥有可计量、成本低、高效、可信等突出特点,基于Hadoop的应用已经遍地开花,尤其是在互联网领域。
本章接下来介绍了Hadoop项目及其结构,现在Hadoop已经发展成为一个包含多个子项目的集合,被用于分布式计算,虽然Hadoop的核心是Hadoop分布式文件系统和MapReduce,但Hadoop下的Common、Avro、Chukwa、Hive、HBase等子项目提供了互补性服务或在核心层之上提供了更高层的服务。紧接着,简要介绍了以HDFS和MapReduce为核心的Hadoop体系结构。
本章最后介绍了Hadoop的数据管理,主要包括Hadoop的分布式文件系统HDFS、分布式数据库HBase和数据仓库工具Hive的数据管理。它们都有自己完整的数据定义和体系结构,以及实现数据从宏观到微观的立体管理数据方法,这都为Hadoop平台的数据存储和任务处理打下了基础。本章中的许多内容在本书后面的章节中都会详细展开介绍。