2.3 大数据架构
基于上述大数据的特征,通过传统 IT技术存储和处理大数据成本高昂。一个企业要大力发展大数据应用首先需要解决两个问题:一是低成本、快速地对海量、多类别的数据进行抽取和存储;二是使用新的技术对数据进行分析和挖掘,为企业创造价值。因此,大数据的存储和处理与云计算技术密不可分,在当前的技术条件下,基于分布式系统的Hadoop,被认为是最适合处理大数据的技术平台。Hadoop提供的功能:利用服务器集群,根据用户的自定义业务逻辑,对海量数据进行分布式处理。广义上来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈。Hadoop生态圈如图2.3所示。
图2.3 Hadoop 生态圈
各组件简介如下。
1.主要模块
(1)HDFS:分布式文件系统。
(2)MAPREDUCE:分布式运算程序开发框架,用于大规模数据集的并行计算。
(3)HBASE:基于 Hadoop的分布式海量数据库,可以将结构化数据文件映射为数据库表,并提供常用的SQL支持。Hive查询引擎将SQL语句转化为Hadoop平台的MapReduce任务运行。
2.数据管道
(1)Sqoop:主要用于跟关系数据库进行数据交互,通过JDBC方式实现数据迁移。
(2)Flume:Cloudera提供的日志收集框架,用于将海量日志数据并行导入HDFS或者Hive中。
(3)DistCp:一般用于在两个HDFS集群中传输数据,但目前此命令只支持同版本下集群数据迁移,主要用于冷热数据迁移、测试等场景。
(4)Scribe:Facebook开源的日志收集系统,它能够从各种日志源上收集日志,存储到一个中央存储系统(可以是 NFS,分布式文件系统等)上,以便于进行集中统计分析处理。它为日志的“分布式收集,统一处理”提供了一个可扩展的、高容错的方案。
3.数据分析
(1)Hive:提供了一套类数据库的数据存储和处理机制,并采用 HQL(类 SQL )语言对这些数据进行自动化管理和处理。Hive中的海量结构化数据被看成一个个的表,而实际上这些数据是分布式存储在HDFS中的。注意,Hive是离线查询工具,由于其内部机制,需要把 SQL转换成MapReduce后进行分布式查询,所以最短查询时间也需要十几秒,适用于海量数据场景,不适合即时查询需求。
(2)Impala:Impala是Google Dremel的Java实现版本之一。Dermel由Google设计开发,最显著的特性就是支持SQL方式在秒级别分析TB级别数据(1TB数据3秒完成分析计算)。Impala1.0版本完全兼容SQL92规范,不同于Hive将SQL转换为MapReduce方式,Impala通过与商用并行关系数据库中类似的分布式查询引框架(由 Query Planner、Query Coordinator和Query Exec Engine三部分组成,与MR相似的技术架构,但即时性更好),可以直接从HDFS或者HBase中用SELECT、JOIN和统计函数查询数据,性能是Hive(0.81)的3~90倍,目前刚发布的Hive1.0在原有性能上有很大提升,都属于数据仓库工具,但Impala架构更先进。
(3)Pig:Apache Pig是一个分析大规模数据集的平台,其使用场景和Hive相似,Hive更简单,使用类SQL进行数据分析,Pig使用脚本语言,编程性更强,具体选择主要依靠程序员的熟悉程度及场景复杂度决定。
(4)Mahout:主要用于并行数据挖掘,该框架对目前主流数据挖掘算法都已经基于MapReduce进行了实现,节省很多额外开发时间。如推荐引擎、用户关系引擎、GiS热点聚类都可以基于此框架算法来实现。
(5)Scalding:使用Scala编程语言封装MapReduce编程模型,支持DSL(domain-specific language)语法编程,易用性大大提升。主要用于高并发简单ETL处理场景。
4.任务调度
(1)Oozie:其作用就是将多个 MapReduce作业连接到一起,作为一个工作流程执行。一般情况下,一个大型任务由多个 MapReduce组成。如果不用 Oozie,需要手动编写大量连接和转换代码,用于串联起多个MR任务流程,比较耗时,出错率和维护率也比较高。Oozie通过xml方式配置连接起整个任务流程。与传统工作流引擎作用相似。
(2)Azkaban:美国知名互联公司Linkedin发布的开源产品,属于 Oozie的同类产品,在细节上有区别。
5.管理
Hue:它是运营和开发Hadoop应用的图形化用户界面。对单独的用户来说不需要额外的安装。另外,Hue具备简单的权限和用户管理功能,这是其他开源UI不具备的。
Hadoop是一个分布式的基础架构,能够让用户方便高效地利用运算资源和处理海量数据,目前已在很多大型互联网企业得到了广泛应用,如亚马逊、Facebook、Yahoo等。它是一个开放式的架构,架构成员也在不断扩充完善中。
Hadoop是一个开发和运行处理大规模数据的软件平台,属于 Apache开源组织,用Java语言开发,用于实现在大量计算机组成的集群中对海量数据进行分布式存储和计算。Hadoop最核心的设计包含两个模块:HDFS和MapReduce。其中HDFS提供海量数据的存储,MapReduce提供海量数据的分布式计算能力。
2.3.1 HDFS系统
1. HDFS系统的概念和特性
首先,HDFS系统是一个文件系统,用于存储文件,通过统一的命名空间——目录树来定位文件。其次,HDFS系统是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS系统在大数据中的应用是为各类分布式运算框架提供数据存储服务,将大文件、大批量文件,分布式存放在大量的服务器上,以便于采取分而治之的方式对海量数据进行运算分析。
HDFS系统的特性如下。
(1)有高容错性的特点。
(2)整个系统部署在低廉的硬件上。
(3)提供高传输率来访问应用程序的数据。
(4)适合超大数据集的应用程序。
(5)流式数据访问。
HDFS本身是软件系统,不同于传统硬盘和共享存储介质,在文件操作上有其不同之处。
(1)不支持文件随机写入。支持随机读,但没有随机写入机制,这与HDFS文件写入机制有关,所以不支持断点续传等功能。
(2)需要客户端与HDFS交互。目前已有开源支持HDFSmount到Linux服务器上,但性能非常不好。
(3)适合大文件读取场景。因为其分块冗余存储机制,其存储架构在处理小于其分块文件大小的文件时,会浪费管理节点资源,导致效率低。
(4)吞吐和并发具备横向扩展能力。单节点系统比传统硬盘效率低很多,但在大量机器集群环境下,其吞吐和并发能力可以线性提升,远远高于单一硬件设备。
(5)不适合高响应系统。由于HDFS是为高数据吞吐量应用而设计的,以高延迟为代价。
2. HDFS的结构
HDFS中有3个重要角色:NameNode、DataNode和Client,如图2.4所示。
图2.4 HDFS结构
对外部客户机而言,HDFS就像一个传统的分级文件系统,可以删除、移动或重命名文件等。但是HDFS架构是基于一组特定的节点构建的,这是由它自身的特点决定的。这些节点包括NameNode(仅1个),它在HDFS内部提供元数据服务;DataNode为HDFS提供存储块。
存储在HDFS中的文件被分成块,然后将这些块复制到多台计算机中(DataNode)。这与传统的RAID架构大不相同。块的大小(通常为64MB)和复制的块数量在创建文件时由客户机决定。NameNode可以控制所有文件操作。HDFS内部的所有通信都基于标准的TCP/IP协议。
1)NameNode
NameNode是一个通常在HDFS实例中的单独机器上运行的软件。它负责管理文件系统名称空间和控制外部客户机的访问。NameNode决定是否将文件映射到DataNode上的复制块上。对于最常见的3个复制块,第一个复制块存储在同一机架的不同节点上,最后一个复制块存储在不同机架的某个节点上。Metadata所有的相关服务都是由NameNode提供,包括 filename->block(namespace),以及 block->DataNode的对应表。其中,前者通过FsImage写入本地文件系统中,而后者是通过每次HDFS启动时,DataNode进行blockreport后在内存中重构的数据结构。
实际的I/O实务并没有经过NameNode,只有表示DataNode和块的文件映射的元数据经过NameNode。当外部客户机发送请求要求创建文件时,NameNode会以块标识和该块的第一个副本的DataNode的IP地址作为响应。这个NameNode还会通知其他将要接收该块的副本的DataNode。
NameNode在一个称为 FsImage的文件中存储所有关于文件系统名称空间的信息。这个文件和一个包含所有事务的记录文件(EditLog)将存储在NameNode的本地文件系统上。FsImage和EditLog文件也需要复制副本,以防文件损坏或NameNode系统走失。
2)DataNode
DataNode也是一个通常在HDFS实例中的单独机器上运行的软件。Hadoop集群中包含一个 NameNode和大量 DataNode。DataNode通常以机架的形式组织,机架通过一个交换机将所有系统连接起来。
DataNode响应来自HDFS客户机的读写请求。并且还响应来自NameNode的创建、删除和复制块的命令。NameNode依赖来自每个 DataNode的定期心跳(Heartbeat)消息。每条消息都包含一个块报告,NameNode可以根据这个报告验证块映射和其他文件系统元数据。
分布式文件存储的数据节点,存储着文件块(Block),而文件是由文件块组成的,每个块存储在多个(可配,默认为3)不同的DataNode可以提高数据的可靠性。
如果客户机想将文件写到HDFS上,首先需要将文件缓存到本地的临时存储区。如果缓存的数据大于所需的HDFS块大小,创建文件的请求将发送给 NameNode。NameNode将以 DataNode标识和目标块响应客户机。同时也通知将要保存文件块副本的DataNode。当客户机开始将临时文件发送给第一个 DataNode时,将立即通过管道方式将块方式内容转发副本DataNode。客户机也负责创建保存在相同HDFS名称空间中的校验文件。在最后的文件块发送后,NameNode将文件创建提交到它的持久化数据存储(EditLog和FsImage文件)。
3)Client
用于实现客户端文件存储的所有操作,包括文件的增删以及查询等。
3. HDFS文件写入与读取
HDFS文件的写入流程如图2.5所示。
图2.5 HDFS文件的写入流程
(1)客户端通过Distributed FileSystem上的create()方法指明一个欲创建的文件的文件名,然后client通过RPC方式与NameNode通信创建一个新文件映射关系。
(2)客户端写数据:FSData OutputStream把写入的数据分成包(packet),放入一个中间队列——数据队列(data queue)中去。OutputStream从数据队列中取数据,同时向NameNode申请一个新的block来存放它已经取得的数据。NameNode选择一系列合适的DataNode(个数由文件的replication数决定,默认为3,构成一个管道线(pipeline),所以管道线中就有3个 DataNode。OutputStream把数据流式地写入到管道线中的第一个DataNode中,第一个DataNode再把接收到的数据转到第二个DataNode中,以此类推。
(3)FSData OutputStream同时也维护着另一个中间队列——确认队列(ack queue),确认队列中的包只有在得到管道线中所有的DataNode的确认以后才会被移出确认队列。
(4)所有文件写入完成后,关闭文件写入流。
从以上文件写入流程,可以总结出HDFS文件写入具备如下特性。
● 响应时间比较长。
● 文件写入效率与block块数和集群数量相关。
HDFS文件的读取流程如图2.6所示。
图2.6 HDFS文件的读取流程
(1)打开文件流(open())。
(2)从NameNode读取文件块位置列表。
(3)FSDataInputSteam打开read()方法。
(4)根据文件块与DataNode的映射关系。
(5)从不同的DataNode中并发读取文件块。
(6)文件读取完毕,关闭input流。
因为冗余机制,当HDFS文件读取压力比较大的时候,可以通过提高冗余数的方式,NameNode可以通过轮询方式,分配不同client访问不同DataNode上的相同文件块,提升整体吞吐率。
Hadoop在创建新文件时是如何选择block的位置的呢,综合来说,要考虑带宽(包括写带宽和读带宽)和数据安全性,如图2.7所示。
图2.7 选择block的位置
如果把3个备份全部放在一个 DataNode上,虽然可以避免写带宽的消耗,但几乎没有提供数据冗余带来的安全性,如果这个 DataNode宕机,那么这个文件的所有数据就全部丢失了。另一个极端情况是,如果把3个冗余备份全部放在不同的机架上,甚至数据中心里面,虽然这样做数据很安全,但写数据会消耗很多的带宽。HDFS提供了一个默认备份分配策略:把第一个备份放在与客户端相同的DataNode上,第二个放在与第一个不同机架的一个随机DataNode上,第三个放在与第二个相同机架的随机DataNode上。如果备份数大于3,则随后的备份在集群中随机存放,Hadoop会尽量避免过多的备份存放在同一个机架上。
2.3.2 MapReduce
MapReduce是 Google提出的并行计算架构,用于大规模数据集(TB级以上)的并行运算。此算法的计算能力,随着计算节点的数量增加而线性上升。
图2.8表示一个MapReduce计算处理思路,可以简要分解为两部分,数据分块映射处理(Map)和数据结果聚合(Reduce)两个步骤,源数据可以存储在HDFS或者第三方数据源上,计算过程临时数据存储在HDFS和内存中,最终获得我们需要的计算结果,其具体处理流程如图2.9所示。
图2.8 MapReduce计算处理思路
图2.9 MapReduce计算处理流程
1. Map端
(1)每个输入分片会让一个Map任务来处理,默认情况下,以HDFS的一个块的大小(默认为64MB)为一个分片,当然我们也可以自行设置块的大小。Map输出的结果会暂时放在一个环形内存缓冲区中(该缓冲区的大小默认为100MB),当该缓冲区快要溢出时(默认为缓冲区大小的80%),会在本地文件系统中创建一个溢出文件,将该缓冲区中的数据写入这个文件。
(2)在写入磁盘之前,线程首先根据 Reduce任务的数目将数据划分为相同数目的分区,也就是一个 Reduce任务对应一个分区的数据。这样做是为了避免有些 Reduce任务分到大量数据,而有些 Reduce任务却分到很少数据,甚至没有分到数据的尴尬局面。其实分区就是对数据进行 Hash的过程。然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行 Map合并操作,这样做的目的是让尽可能少的数据写入磁盘。
(3)当Map任务输出最后一个记录时,可能会有很多溢出文件,这时需要将这些文件合并。合并的过程中会不断地进行排序和合并操作,目的有两个:①尽量减少每次写入磁盘的数据量;②尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,可以将数据压缩。
(4)将分区中的数据复制给相对应的Reduce任务。Map任务一直和其父 TaskTracker保持联系,而 TaskTracker又一直和JobTracker保持心跳。所以 JobTracker中保存了整个集群中的宏观信息。Reduce任务只需向JobTracker获取对应的Map输出位置。
2. Reduce端
(1)Reduce会接收到不同的Map任务传来的数据,并且每个 Map传来的数据都是有序的。如果 Reduce端接收的数据量相当小,则直接存储在内存中,如果数据量超过了该缓冲区大小的一定比例,则对数据合并后溢写到磁盘中。
(2)随着溢写文件的增多,后台线程会将它们合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。其实不管在Map端还是 Reduce端,MapReduce都是反复地执行排序、合并操作,这就是为什么有些人会说:排序是Hadoop的灵魂。
(3)合并的过程中会产生许多中间文件(写入磁盘了),但 MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到Reduce函数。
3. Shuffle
在Hadoop的集群环境中,大部分Map任务和Reduce任务是在不同的Node上执行,主要的开销是网络开销和磁盘I/O开销,因此Shuffle的主要作用如下。
(1)完整地从Map端传输到Reduce端。
(2)跨节点传输数据时,尽可能减少对带宽的消耗(注意是 Reduce执行的时候去拉取Map端的结果)。
(3)减少磁盘I/O开销对任务的影响。
2.3.3 HBase
HBase是Google Bigtable的开源实现版本。数据存储在HDFS中,继承了HDFS的高可靠性、可伸缩架构,同时自己实现了高性能、列存储、实时读写的特性。
不同于HDFS的高吞吐低响应,HBase设计用于高并发读写场景。
(1)HBase基于HadoopHDFSappend方式进行数据追加操作,非常适合列族文件存储架构。
(2)HBase写请求,都会先写redo log,然后更新内存中的缓存。缓存会定期地刷入HDFS。文件基于列创建,因此任何一个文件(MapFile)只包含一个特定列的数据。
(3)当某一列的MapFile数量超过配置的阈值时,一个后台线程就开始将现有的MapFile合并为一个文件,这个操作叫 Compaction。在合并的过程中,读写不会被阻塞。
(4)读操作会先检查缓存,若未命中,则从最新的MapFile开始,依次往最老的MapFile找数据。可以想象一次随机读操作可能需要扫描多个文件。
HBase的文件和日志确实都存储在HDFS中,但通过精致设计的算法实现了对高并发数据随机读写的完美支持,这依赖于 HBase数据排序后存储的特性。与其他的基于 Hash寻址的NoSQL数据库有很大不同。
在使用特性上,原生 HBase不支持 JDBC驱动,也不支持 SQL方式进行数据查询,只有简单的PUT和GET操作。数据查询通过主键(rowkey)索引和Scan查询方式实现,在事务上,HBase支持单行事务(可通过上层应用和模块如hive或者coprocessor来实现多表join等复杂操作)。HBase主要用来存储非结构化和半结构化的松散数据,如图2.10所示。
图2.10 HBase的架构
HBase中的表一般有以下特点。
(1)大:一个表可以有上亿行,上百万列。
(2)面向列:面向列(族)的存储和权限控制,列(族)独立检索。
(3)稀疏:对于为空(null)的列,并不占用存储空间(每个列族是一个文件,没内容的情况下不会占用空间),因此,表可以设计得非常稀疏。
(4)HBase适用于海量高并发文本数据写入、存储、查询需求场景,这些数据量是传统数据库难以满足的,以下列了一些适用场景。
(5)详单管理、查询。
(6)GiS数据存储、统计。