Hive是Hadoop生态系统中必不可少的一个工具,它提供了一种SQL方言,可以查询存储在Hadoop分布式文件系统(HDFS)中的数据或其它和hadoop集成的文件系统,如果MapR-FS,Amazon S3和像HBase(Hadoop数据库)和Cassandra这样的数据库中的项目。
大多数数据仓库应用程序都是使用关系型数据库进行实现的,并使用SQL作为查询语言。Hive降低了将这些应用程序转移到Hadoop系统上的难度。凡是会使用SQL语言的开发人员都可以轻松地学习并使用Hive。如果没有Hive,那么这些用户就必须学习心得语言和工具,然后才能应用到生产环境中。如果没有Hive,那么开发者将面临一个艰巨的挑战,如果将他们的SQL应用程序移植到Hadoop上。
Hadoop生态系统就是为处理如此大数据集而产生的一个合乎成本效益的解决方案。Hadoop实现了一个特别的计算模型,也就是MapReduce,其可以将计算任务分割成多个处理单元后分散到一群家用的或服务器级别的硬件机器上,从而降低成本并提供水平伸缩性。这个计算模型的下面是一个被称为Hadoop分布式文件系统(HDFS)的分布式文件系统。这个文件系统是“可插拔的”,而且现在已经出现了几个商用的和开源的替代方案。
不过,仍然存在一个挑战,那就是用户如何从一个现有的数据基础架构转移到Hadoop上,而这个基础架构是基于传统关系型数据库和结构化查询语言(SQL)的。对于大量的SQL用户来说,这个问题又如何解决那?
这就是Hive出现的原因。Hive提供了一个被称为Hive查询语言(简称HiveQL或HQL)的SQL方言,来查询存储在Hadoop集群中的数据。
SQL知识分布广泛的一个原因是:它是一个可以有效地,合理地且直观地组织和使用数据的模型。即使对于经验丰富的java开发工程师来说,将这些常见的数据运算对于到底层的map
Reduce java api也是令人畏缩的。Hive可以帮助用户来做这些苦活,这样用户就可以集中精力关注查询本身了。Hive可以将大多数的查询转换为mapreduce任务,进而在介绍一个令人熟悉的SQL抽象的同时,拓宽Hadoop的可扩展性。
Hive最适合数据仓库应用程序,使用该应用程序进行相关的静态数据分析,不需要快速响应给出结果,而且数据本身不会频繁变化。
Hive不是一个数据库。Hadoop以及HDFS的设计本身约束和局限性地限制了Hive所能胜任的工作。其中最大的限制就是Hive不支持记录级别的更新,插入或者删除操作。但是用户可以通过查询生成新表或者将查询结果导入到文件中。同时,因为Hadoop是一个面向批处理的系统,而MapReduce任务(job)的启动过程需要消耗较长的时间,所以Hive查询延时比较严重。传统数据库中在秒级别可以完成查询,在Hive中,即使数据集相对较少,往往也需要更长时间。最后需要说明的是:Hive不支持事务。
因此,Hive不支持OLTP(联机事务处理)所需的关键功能,而更接近成为一个OLAP(联机分析)工具。但是我们将会看到,由于Hadoop本身的视角开销很大,并且Hadoop所被设计用来处理的数据规模非常大,因此提交查询和返回结果是可能具有非常大的延时的,所以Hive并没有满足OLAP中的“联机”部分,至少目前并没有满足。
如果用户需要对大规模数据使用OLTP功能的话,那么应该选择使用一个NoSQL数据库,例如,和Hadoop结合使用的HBase及Cassandra。如果用户使用的是Amazon的弹性mapreduce计算系统(EMR)或者弹性计算云服务(EC2)的话,也可以使用DynamoDB。用户甚至可以和这些数据库结合起来使用Hive。
因此,Hive是最适合数据仓库应用程序的,其可以维护海量数据,而且可以对数据进行挖掘,然后形成意见报告。
因为大多数的数据仓库应用程序是使用基于SQL的关系型数据库实现的,所以Hive降低了这些应用程序移植到Hadoop上的障碍。如果用户懂SQL,那么学习使用Hive非常容易。如果没有Hive,那么这些用户就需要去重新学习新的语言和新的工具才能进行生产。
同样地,相对于其他Hadoop语言和工具来说,Hive也使得开发者将基于SQL的应用程序移植到Hadoop变得更加容易。
不过,和大多数SQL方言一样,HiveQL并不符合ANSI SQL标准,其和Oracle,MySQL,SQL Server支持的常规SQL方言在很多方面存在差异(不过,HiveQL和MySQL提供的SQL方言最接近)。
MapReduce是一种计算模型,该模型可讲大型数据处理任务分解成很多单个的,可以在服务器集群中并行执行的任务。这些任务的计算结果可以合并在一起来计算最终的结果。
MapReduce编程模型是由google开发的。Google通过一篇很有影响力的论文对这个模型进行了描述,《MapReduce:大数据之上的简化数据处理》。一年后,一篇名为《Google文件系统》的论文介绍了Google文件系统。这两篇论文启发了Doug Cutting开发了hadoop。
事实上,许多这些底层细节实际上进行的是从一个任务(job)到下一个任务(job)的重复性工作,例如,将Mapper和Reducer一同写入某些数据操作构造这样的底层的繁重的工作,通过过滤得到所需数据的操作,以及执行类似SQL中数据集键的连接(join)操作等。不过幸运的是,存在一种方式,可以通过使用“高级”工具自动处理这些情况来重用这些通用的处理过程。
这也就是引入Hive的原因。Hive不仅提供了一个熟悉SQL的用户所能熟悉的编程模型,还消除了大量的通用代码,甚至是有时是不得不使用java编写的令人棘手的代码。
这就是为什么Hive对于Hadoop如此重要的原因,无论用户是DBA还是java开发工程师。Hive可以让你花费相当少的精力就可以完成大量的工作。
有好几种方式可以与Hive进行交互。本书中,我们将主要关注于CLI,也就是命令行界面。对于那些更喜欢图形用户界面的用户,可以使用现在逐步出现的商业和开源的解决方案,例如Karmasphere发布的一个商业产品(http://karmasphere.com),Cloudera提供的开源的Hue项目(https://github.com/cloudera/hue),以及Qubole提供的“Hive即服务”方式(http://qubole.com),等。
Hive的模块非常类似于传统的数据库的模块,下面是Hive的必要组成模块以及对应的功能介绍
HiveQL:这是Hive的数据查询语言,与SQL非常类似。Hive提供了这个数据查询语言与用户的接口,包括一个shell的接口,可以进行用户的交互,以及网络接口与JDBC接口。
JDBC接口可以用于编程,与传统的数据库编程类似,使得程序可以直接使用Hive功能而无需更改。
Driver: 执行的驱动,用以将各个组成部分形成一个有机的执行系统,包括会话的处理,查询获取以及执行驱动。
Compiler:Hive需要一个编译器,将HiveQL语言编译成中间表示,包括对于HiveQL语言的分析,执行计划的生成以及优化等工作。
Execution Engine:执行引擎,在Driver的驱动下,具体完成执行操作,包括MapReduce执行,或者HDFS操作,或者元数据操作。
Metastore:用以存储元数据:存储操作的数据对象的格式信息,在HDFS中的存储位置的信息以及其他的用于数据转换的信息SerDe等。
Hive发行版中附带的模块有CLI,一个称为Hive网页界面(HWI)的简单网页界面,以及可通过JDBC、ODBC和一个Thrift服务器(参考第16章)进行编程访问的几个模块。
所有的命令和查询都会进入到Driver(驱动模块),通过该模块对输入进行解析编译,对需求的计算进行优化,然后按照指定的步骤执行(通常是启动多个MapReduce任务来执行)。当需要启动mapreduce任务时,Hive本身是不会生成Java MapReduce算法程序的。相反,Hive通过一个表示“job执行计划”的XML文件驱动执行内置的,原生的Mapper和Reducer模块。换句话说,这些通用的模块函数类似于微型的语言翻译程序,而这个驱动计算的“语言”是以XML形式编码的。
Hive通过和JobTracker通信来初始化MapReduce,而不必部署在JobTracker所在的管理节点上执行。在大型集群中,通常会有网关机专门用于部署像Hive这样的工具。在这些网关机上可远程和管理节点上的JobTracker通信来执行任务(job)。通常,要处理的数据文件是存储在HDFS中的,而HDFS是由NameNode进行管理的。
Metastore(元数据存储)是一个独立的关系型数据库(通常是一个MySQL实例),Hive会在其中保存表模式和其它系统元数据。
尽管本书是关于Hive的,不过还是有必要提及其他的一些高级工具,这样用户可以根据需求进行选择。Hive最适合于数据仓库程序,对于数据仓库程序不需要实时响应查询,不需要记录级别的插入,更新和删除。
Hive的替代工具中最有名的就是Pig了(请参考http://pig.apache.org)。Pig是由Yahoo!开发完成的,而同时期Fackbook正在开发Hive。Pig现在同样也是一个和Hadoop紧密联系的顶级Apache项目。
假设用户的输入数据具有一个或者多个源,而用户需要进行一组复杂的转换来生成一个或者多个输出数据集。如果使用Hive,用户可能会使用嵌套查询(正如我们将看到的)来解决这个问题,但是在某些时刻会需要重新保存临时表(这个需要用户自己进行管理)来控制复杂度。
Pig被描述成一种数据流语言,而不是一种查询语言。在Pig中,用户需要写一系列的声明语句来定义某些关系和其他一些关系之间的联系,这里每个新的关系都会执行新的数据转换过程。Pig会查找这些声明,然后创建一系列有次序的MapReduce任务(job),来对这些数据进行转换,直到产生符合用户预期的计算方式所得到的最终结果。
这种步进式的数据“流”可以比一组复杂的查询更加直观。也因此,Pig常用于ETL(数据抽取,数据转换和数据装载)过程的一部分,也就是将外部数据装载到Hadoop集群中,然后转换成所期望的数据格式。
Pig的一个缺点就是其所使用的定制语言不是基于SQL的。这是可以理解的,因为Pig本身就不是被设计为一种查询语言的,但是这也意味着不适合将SQL应用程序移植到Pig中,而经验丰富的SQL用户可能需要投入更高的学习成本来学习Pig。
然而, Hadoop团队通常会将Hive和Pig结合使用,对于特定的工作选择合适的工具。
如果用户需要Hive无法提供的数据库特性(如行级别的更新,快速的查询响应时间,以及支持事务)的话,那么该怎么办呐?
HBase是一个分布式的,可伸缩的数据存储,其支持行级别的数据更新,快速查询和行级事务(但不支持多行事务)。
HBase的设计灵感来自于Google的BigTable,不过HBase并没有实现BigTable的所有特性。HBase支持的一个重要特性就是列存储,其中的列可以组织成列族。列族在分布式集群中物理上是存储在一起的。这就使得当查询场景涉及的列只是所有列的一个子集时,读写速度会快得多。因为不需要读取所有的行然后丢弃大部分的列,而是只需读取需要的列。
可以像键-值存储一样来使用HBase,其每一行都使用了一个唯一键来提供非常快的速度读写这一行的列或者列族。HBase还会对每个列保留多个版本的值(按照时间戳进行标记),版本数量是可以配置的,因此,如果需要,可以“时光倒流”回退到之前的某个版本的值。
最后,HBase和Hadoop之间是什么关系?HBase使用HDFS来持久化存储数据。为了可以提供行级别的数据更新和快速查询,HBase也使用了内存缓存技术对数据和本地文件进行追加数据更新操作日志。持久化文件将定期地使用附加日志更新进行更新等操作。
HBase没有提供类似于SQL的查询语言,但是Hive现在已经可以和HBase结合使用了。
Apache Hadoop生态系统之外还有几个“高级”语言,它们也在Hadoop之上提供了不错的抽象来减少对于特定任务(job)的底层编码工作。为了叙述的完整性,下面我们列举其中的一些来进行介绍。所有这些都是JVM(Java虚拟机)库,可用于像Java、Clojure、Scala、JRuby、Groovy和Jython,而不是像Hive和Pig一样使用自己的语言工具。
因为Hadoop是面向批处理系统的,所以存在更适合事件流处理的使用不同的分布式计算模式的工具。对事件流进行处理时,需要近乎“实时”响应。
没有使用MapReduce的分布式处理工具如下:
名称 |
URL |
描述 |
Spark |
|
一个基于Scala API的分布式数据集的分布式计算框架。其可以使用HDFS,而且对于MapReduce中多种计算可以提供显著的性能改进。同时还有一个将Hive指向Spark的项目,称作Shark。 |
Storm |
|
一个实时事件流处理系统 |
Kafka |
|
一个分布式的发布-订阅消息传递系统。 |
最后,当无需一个完整的集群时(例如,处理的数据集很小,或者对于执行某个计算的时间要求并不苛刻),还有很多可选的工具可以轻松地处理原型算法或者对数据子集进行探索。表1-3列举了一些相对比较热门的工具。
Hive二进制分支版本核心包括3个部分。主要部分是Java代码本身。在$HIVE_HOME/lib目录下可以发现众多的JAR(Java压缩包)文件,例如hive-exec*.jar和hive-metastore*.jar。每个JAR文件都实现了Hive功能中某个特定的部分。
$HIVE_HOME/bin目录下包含可以执行各种各样Hive服务的可执行文件,包括hive命令行界面(简称CLI)。CLI是我们使用Hive最常用的方式。
Hive还有一些其它组件。Thrift服务提供了可远程访问其他进程的功能,也提供使用JDBC和ODBC访问Hive的功能。这些都是基于Thrift服务实现的。
所有的Hive客户端都需要一个metastoreservice(元数据服务),Hive使用这个服务来存储表模式信息和其它元数据信息。通常情况下会使用一个关系型数据库中的表来存储这些信息。默认情况下,Hive会使用内置的DerbySQL服务器,其可以提供有限的,单进程的存储服务。例如,当使用Derby时,用户不可以执行2个并发的Hive CLI实例,然而,如果在个人计算机上或某些开发任务上使用的话也是没有问题的。对于集群来说,需要使用MySQL或者类似的关系型数据库。
最后,Hive还提供了一个简单的网页界面,也就是Hive网页管理界面(HWI),提供了远程访问Hive的服务。
在分布式模式下,集群中会启动多个服务。JobTracker管理着job,而HDFS则由NameNode管理着。每个工作节点上都有job task在执行,由每个节点上的TaskTracker服务管理着;而且每个节点上还存有分布式文件系统中的文件数据块,由每个节点上的DataNode服务管理着。
Hive所需要的组件中只有一个外部组件是Hadoop没有的,那就是metastore(元数据存储)组件。元数据存储中存储了如果表的模式和分区信息等元数据信息。用户在执行如create table x…或者alter talbe y…等命令时会指定这些信息。因为多用户和系统可能需要并发访问元数据存储,所有默认的内置数据库并不适用于生产环境。
任何一个适用于JDBC进行连接的数据块都可以用作元数据存储。在实践中,大多数的Hive客户端会使用MySQL。
像表的模式信息,分区信息等这些必须的元数据,其信息量是很小的,通常比存储在Hive中的数据的量要少的多。因此,用户其实无需为元数据存储提供一个强劲的专用数据库服务器。
Hive变量内部是以Java字符串的方式存储的。
Hive支持关系型数据库中的大多数基本数据类型,同时也支持关系型数据库中很少出现的3中集合数据类型。
当用户向传统数据库中写入数据的时候,不管采用装载外部数据的方式,还是采用将一个查询的输出结果写入的方式,或者是使用update语句等,数据库对于存储都具有完全的控制力。数据库就是“守门人”。传统数据库是写时模式(schema on write),即数据在写入数据库时对模式进行检查。
Hive对底层存储并没有这样的控制。对于Hive要查询的数据,有很多方式对其进行创建,修改,甚至损坏。因此,Hive不会在数据加载时进行验证,而是在查询时进行,也就是读时模式(schema on read)。
HiveQL是Hive的查询语言。和普通使用的所有SQL方言一样,它不完全遵守任一种ANSI SQL标准的修订版。HiveQL可能和MySQL的方言最接近。但是两者还是存在显著性差异的。Hive不支持行级插入操作,更新操作和删除操作。Hive也不支持事务。
Hive中数据库的概念本质上仅仅是表的一个目录或者命名空间。
Hive会为每个数据库创建一个目录。数据库中的表将会以这个数据库目录的子目录形式存储。有一个礼物就是default数据库中的表,因为这个数据库本身没有自己的目录。
管理表有时也称为内部表。因为这种表,Hive会控制着数据的生命周期。当我们删除一个管理表时,Hive也会删除这个表的数据。
表是外部的,Hive并非人为其完全拥有这份数据。因此删除该表并不会删除这份数据,不过描述表的元数据信息会被删除掉。
管理表和外部表有一个区别,即HiveQL语法结构并不适合于外部表。
好的软件设计的一般原则是表达意图。如果数据会被多个工具共享,那么可以创建一个外部表,来明确对数据的所有权。
数据分区的一般概念存在已久。其可以有多种形式,但是通常使用分区来水平分散压力,将数据从物理上转移到和使用最频繁的用户更近的地方,以及实现其他目的。
Hive中有分区表的概念。可以看到分区表具有重要的性能优势,而且分区表还可以将数据以一种符合逻辑的方式进行组织,比如分层存储。
对于数据进行分区,也许最重要的原因就是为了更快地查询。
Hive默认存储格式是文本文件格式,这个也可以通过可选的字句STORED AS TEXTFILE显示指定。使用TEXTFILE就意味着,每一行被认为是一个单独的记录。
用户可以将TEXTFILE替换为其他Hive所支持的内置文件格式,包括SEQUENCEFILE和RCFILE,这两种文件格式都是使用二进制编码和压缩来优化磁盘空间使用以及I/O带宽性能。
对于记录是如何被编码成文件的,以及列式如何被编码为记录的,Hive指出了它们之间的不同。
记录编码是通过一个inputformat对象来控制的。
记录的接卸是由序列化器/反序列器(或者缩写为SerDe)来控制的。
Hive使用一个inputformat对象将输入流分割成记录,然后使用一个outputformat对象来将记录格式化为输入流,在使用一个SerDe在读数据时将记录解析成列,在写数据时将列编码成记录。
删除管理表,表的元数据信息和表内的数据都会被删除。
删除外部表,表的元数据信息会被删除,但是表中的数据不会被删除。
Alter table仅仅会修改表元数据,表数据本身不会有任何修改。
HiveQL就是Hive查询语言,并关注于向表中装载数据和从表中抽取数据到文件系统的数据操作语言部分。
既然Hive没有行级别的数据插入,数据更新和删除操作,那么往表中装载数据的唯一途径就是使用“大量”的数据装载操作。或者通过其他方式将文件写入到争取的目录下。
Hive并不会验证用户装载的数据和表的模式是否匹配。然后,Hive会验证文件格式是否和表结构定义的一致。例如,如果表在创建时定义的存储格式是SEQUENCEFILE,那么装载进去的文件也应该是Sequencefile格式的才行。
视图可以允许保存一个查询并像对代表一样对这个查询进行操作。这是一个逻辑结构,因为它不像一个表会存储数据。换句话说,Hive目前不支持物化视图。
对于视图来说一个常见的使用场景就是基于一个或多个列的值来限制输出结果。有些数据库允许将视图作为一个安全机制,也就是不给用户直接访问具有敏感数据的原始表,而是提供给用户一个通过WHERE字句限制了的视图,以供访问。Hive目前并不支持这个功能,因为用户必须具有能够访问整个底层原始表的权限,这时视图才能工作。然后,通过创建视图来限制数据访问可以用来保护信息不被随意查询。
视图是只读的。对于视图只允许改变元数据中TBLPROPERTIES属性信息。
Hive只有有限的索引功能。Hive中没有普通关系型数据库中键的概念,但是还是可以对一些字段建立索引来加速某些操作的。一张表的索引数据存储在另外一张表中。
当逻辑分区实际上太多而几乎无法使用时,建立索引也就成为分区的另一个选择。建立索引可以帮助裁剪掉一张表的一些数据块,这样能够减少MapReduce的输入数据量。并非所有的查询都可以通过建立索引获得好处。通过EXPLAIN命令可以查看某个查询语句是否用到了索引。
Hive中的索引和关系型数据库一样,需要进行仔细评估才能使用。维护索引也需要额外的存储空间,同时创建索引也需要消耗计算资源。用户需要在建立索引为查询带来的好处和因此而需要付出的代价之间做出权衡。
Hive中分区的功能是非常有用的。这是因为Hive通常要对数据进行全盘扫描,来满足查询条件。通过创建很多的分区确实可以优化一些查询。
HDFS用于设计存储数百万的大文件,而非数十亿的小文件。使用过多分区可能导致的一个问题就是会创建大量的非必须的Hadoop文件和文件夹。一个分区就对应一个包含多个文件的文件夹。如果指定的表存在数百个分区,那么可能每天都会创建好几万个文件。如果保持这样的表很多年,那么最终会超出NameNode对系统元数据信息的处理能力。因为namenode必须要将所有的系统文件的元数据信息保持在内存中。虽然每个文件只需要少量字节大小的元数据(大约是150字节/文件),但是这样会有限制一个HDFS实例所能管理的文件总数的上限。而其它的文件系统,比如MapR和Amazon S3就没有这个限制。
Mapreduce会将一个任务(job)转换成多个任务(task)。默认情况下,每个task都是一个新的JVM实例,都需要开启和销毁的开销。对于小文件,每个文件都会对于一个task。在一些情况下,JVM开启和销毁的视角中销毁可能会比实际处理数据的时间消耗要长。
因此,一个理想的分区方案不应该导致产生太多的分区和文件夹目录,并且每个目录下的文件应该足够得大,应该是文件系统中块大小的若干倍。
关系型数据库通常使用唯一键,索引和标准化来存储数据集,通常是全部或大部分存储到内存的。然而,Hive没有主键或基于序列秘钥生成的自增键的概念。
很多的ETL处理过程会涉及到多个处理步骤,而每个步骤可能会产生一个多个临时表,这些表仅供下一个job使用。起先可能会觉得这些临时表进行分区不是那么有必要的。不过,想象一下这样的场景:由于查询或者原始数据处理的某个步骤出现问题而导致需要对好几天的输入数据重跑ETL过程。这是用户可能就需要执行那些一天执行一次的处理过程,来保证在所有的任务完成之前不会有job将临时表覆盖重写。
一个更具鲁棒性的处理方法是在整个过程中使用分区。
分区提供一个隔离数据和优化查询的遍历的方式。
分桶是将数据集分解成更容易管理的若干部分的另一个技术。
Hive提供了SerDe抽象,其用于从输入中提取数据。SerDe同样用于输出数据,尽管输出功能并发经常使用,因为Hive主要用于查询。一个SerDe通常是从左刀油进行解析的。通过制定的分隔符将行分解成列。
Hive通常使用行式存储,不过Hive也提供了一个列式SerDe来以混合列式格式存储信息。
几乎在所有情况下,压缩都可以使磁盘上存储的数据量变小,这样可以通过降低I/O来提高查询执行速度。Hive可以无缝地使用很多压缩类型。不使用压缩唯一令人信服的理由就是产生的数据用于外部系统,或者非压缩格式(例如文本格式)是最兼容的。
但是压缩和解压缩都会消耗CPU资源。MapReduce任务往往是I/O密集型的,因此CPU开销通常不是问题。不过,对于工作流这样的CPU密集型的场景,例如一些机器学习算法,压缩实际上可能会从更多必要的操作中获取宝贵的CPU资源,从而降低性能。
HiveQL是一种声明式语言,用户会提交声明式的查询,而Hive会将其转换成MapReduce job。
Hive的一个独特功能就是:Hive不会强制要求将数据转换成特定的格式才能使用。Hive利用Hadoop的InputFormat API来从不同的数据源读取数据,例如问个事,Sequence文件格式,甚至用户自定义格式。同样地,使用OutputFormat API也可以将数据写成不同的格式。
尽管Hadoop的文件系统支持对非压缩数据的线性扩展存储,但是对数据进行压缩还是有很大好处的。压缩通常都会节约可观的磁盘空间,例如,基于文本的文件可以压缩40%甚至更高比例。
Hadoop的job通常是I/O密集型而不是CPU密集型的。如果是这样的话,压缩可以提高性能。不过,如果用户的job是CPU密集型的话,那么使用压缩可能会降低执行性能。
使用压缩的优势是可以最小化所需要的磁盘存储空间,以及减少磁盘和网络I/O操作。不过,文件压缩过程和解压缩过程会增加CPU开销。因此,对于压缩密集型的job最好使用压缩,特别是有额外的CPU资源或磁盘存储空间比较稀缺的情况。
所有最新的那些Hadoop版本都已经内置支持GZIP和BZip压缩方案了,包括加速对这些格式的压缩和解压缩的本地Linux库。绑定支持Snappy压缩是最近才增加的。
那么,为什么我们需要不同的压缩方案呢?每一个压缩方案都在压缩/解压缩速度和压缩率间进行权衡。BZip2压缩率最高,但是同时需要消耗最多的CPU开销。GZip是压缩率和压缩/解压缩速度上的下一个选择。
压缩文件缺失能够节约存储空间,但是,在Hadoop中存储裸压缩文件的一个缺点就是,通常这些文件是不可分割的。可分割的文件可以划分成多个部分,由多个mapper并行处理。大多数的压缩文件是不可分割的,也就是只能从头读到尾。
Hadoop所支持的Sequence file存储格式可以将一个文件划分成多个块,然后采用一种可分割的方式对块进行压缩。
Sequence file提供了3种压缩方式:NONE,RECORED,BLOCK。默认是RECORDED级别(也就是记录级别)。通常所说,BLOCK级别(也就是块级别)压缩性能最好而且是可以分割的。
Hadoop中有一种存储格式名为HAR,也就是HadoopArchive(Hadoop归档文件)的简写。一个HAR文件就像在HDFS文件系统中的一个HAR文件一样是一个单独的文件。不过,其内部可以存放多个文件和文件夹。在一些使用场景下,较旧的文件夹和文件比较新的文件夹和文件被访问的概率要低很多。如果某个特定的分区下保存的文件由成千万的话,那么就需要HDFS中的NameNode消耗非常大的代价来管理这些文件。通过将分区下的文件归档成一个巨大的,但是同时可以被Hive访问的文件,可以减轻NameNode的压力。不过缺点是,HAR文件查询效率不高;同时,HAR文件并非是压缩的,因此也不会节约存储空间。
Hive是通过利用或扩展Hadoop的组件功能来运行的,场景的抽象有InputFormat,Outputformat,mapper,reducer,还包含一些一些自己的抽象接口,例如SerDe,用户自定义函数(UDF)和StorageHandles。
这些组件都是Java组件,不过Hive将这些复杂的底层实现隐藏起来了,而提供给用户通过SQL语句执行的方式,而不是使用Java代码。
Streaming提供了另一种处理数据的方式。在streamingjob中,hadoop streaming API会为外部进程开启了一个I/O通道。
其中一种存储格式是SequenceFile文件存储格式,在定义表结构时可以通过STORED AS SEQUENCEFILE语句指定。
SequenceFile文件是含有键值对的二进制文件。当Hive将查询转换成mapreduce job时,对于指定的记录,其取决于使用那些合适的键值对。
Sequencefile是Hadoop本身就可以支持的一种标准文件格式,因为它也是Hive和其它hadoop相关的工具中共享文件的可以接受的选择。
SequenceFile可以在块级别和记录级别进行压缩,这对优化磁盘利用率和I/O来说非常有意义。
Hive所支持的另一种高效的二进制文件格式就是RCFile。
大多数的Hadoop和Hive存储都是行格式存储的,在大多数场景下,这是比较高效的。这种高效归根于如下几个原因:大多数的表具有的字段个数都不大(一般就1到20个字段);对文件按块进行压缩对于需要处理重复数据的情况比较高效,同时很多的处理和调试工具(例如more,head,awk)都可以很好地应用于行式存储的数据。
并非所有的工具和数据存储都是采用行式存储的方式的,对于特定类型的数据和应用来说,采用列式存储有时候更好。例如,如果指定的表具有成本上千个字段,而大多数查询只需要使用到其中一小部分字段,这是扫描所有的行而过滤掉大部分的数据显然是个浪费。然而,如果数据是按照列而不是行进行存储的话,那么只要对其需要的列的数据进行扫描就可以了,这样可以提高性能。
对于列式存储而言,进行压缩通常会非常高效。
------基于这些场景,Hive中才设计了RCFile。
XML天生就是非结构化的,这使得Hive成为XML处理的一个强大的数据库平台。众多原因之一就是大型XML文档解析和处理所需要的复杂性和资源消耗使得Hadoop非常适合作为一个XML数据库平台,因为Hadoop可以并行地处理XML文档,Hive也成为解决XML相关数据的完美工具。
Hive具有一个可选的组件叫做HiveServer或者HiveThrift,其允许通过制定端口访问hive。Thrift是一个软件框架,其用于跨语言的服务开发。Thrift允许客户端使用包括Java,C++,Ruby和其它很多种语言,通过编程的方式远程访问Hive。
访问Hive的最常用方式就是通过CLI进行访问。
Hive通过Thrift提供Hive元数据存储的服务。
Hadoop起源于Apache Nutch的子项目。在哪个时期以及其整个早期原型时期,功能性需求比安全性需求优先级更高。分布式系统的安全问题要比正常情况下更加复杂,因为不同机器上的多个组件需要相互进行通信。
最近对于Hadoop的安全引入多个变化,其中主要是对于Kerberos安全认证的支持,还包含一些其它问题的修复。Kerberos允许客户端和服务端互相认证。客户端的每次请求中都会带有凭证(ticket)信息。在TaskTracker上执行的任务(task)都是由执行任务(job)的用户来执行的。用户无法通过设置hadoop.job.ugi属性的值来模拟其他人来执行任务。为了达到这个目的,所有的Hadoop组件从头到尾都要使用Kerberos安全认证。
Hive是原始的SQL-on-Hadoop解决方案。它是一个开源的Java项目,能够将SQL转换成一系列可以在标准的Hadoop TaskTrackers上运行的MapReduce任务。Hive通过一个metastore(本身就是一个数据库)存储表模式、分区和位置以期提供像MySQL一样的功能。它支持大部分MySQL语法,同时使用相似的 database/table/view约定组织数据集。Hive提供了以下功能:
Hive是一个几乎所有的Hadoop机器都安装了的实用工具。Hive环境很容易建立,不需要很多基础设施。鉴于它的使用成本很低,我们几乎没有理由将其拒之门外。但是需要注意的是,Hive的查询性能通常很低,这是因为它会把SQL转换为运行得较慢的MapReduce任务。
Hortonworks目前正在推进Apache Tez 的开发以便于将其作为新的Hive后端解决现在因为使用MapReduce而导致的响应时间慢的问题。
由Facebook开源,建立在Hadoop基础上的数据仓库基础架构。
将结构化数据文件映射为数据库表。
提供类似SQL的数据查询语句,转换为MapReduce任务执行。
本质是将SQL转换为MapReduce程序。
数据汇总(每天/每周)
非实时分析
数据挖掘
–人员学习成本太高
–项目周期要求太短
–复杂查询与Join用MapReduce实现困难
–操作接口采用类SQL语法,提供快速开发的能力
–避免了去写MapReduce,减少开发人员的学习成本
–扩展功能很方便
–解决“即席查询”问题
–降低平台转移成本,SQL应用平稳过渡
–降低Hadoop使用难度,让SQL技能良好Java技能较弱的程序员可以使用
–海量结构化数据分析(500GB以上RDBMS就难以处理)
–高扩展性
•Hive可以自由的扩展集群的规模,一般情况下不需要重启服务
–高延展性
•Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数
–高容错性
•良好的容错性,节点出现问题SQL仍可完成执行
–将复杂MR任务编写为SQL语句,提高开发效率
–灵活的数据存储,支持
•JSON、CSV、RCFile、ORCFile、SequenceFile、TextFile和自定义格式
–可扩充UDF/UDAF/UDTF
–延迟较高,性能有提升空间
–索引不够完善,效率较低
–不支持事务类操作
Hive支持两种数据类型
–基本(原子)数据类型
–复杂(集合)数据类型
Database:相当于RDB里面的命名空间(namespace),它的作用是将用户和数据库的应用隔离到不同的数据块或模式中。
表(table):
Hive的表逻辑上由存储的数据和描述表格中的数据形式的相关元数据组成。
表存储的数据存放在分布式文件系统(如HDFS)里;元数据存储在关系数据库里。
Hive里的表有两种类型:
(1) 托管表,这种表的数据文件存储在hive的数据仓库里。
(2) 外部表,这种表的数据文件可以存放在hive数据仓库外部的分布式文件系统上,也可以放到hive数据仓库里。
分区:
(1) 是根据“分区列”的值对表的数据进行粗略划分的机制,在hive存储在就体现在表的主目录(hive的表实际上显示就是一个文件夹)下的一个子目录。
(2) 使用分区是为了加快数据分区的查询速度而设计的,我们在查询某个具体分区列里面的数据适合没必要进行全表扫描。
桶(bucket):
(1)table和partition都是目录级别的拆分数据,bucket则是对数据源数据文件本身来拆分数据。
(2)使用桶的表会将源数据文件按一定规律拆分成多个文件
(3)桶是更为细粒度的数据范围划分,它能使一些特定的查询效率更高
•比如对于具有相同的桶划分并且join的列刚好就是在桶里的连接查询
•还有就是示例数据,对于一个庞大的数据集需要拿出来一小部分作为样例
Hive有三种文件格式:
建表时的默认格式,导入数据时会直接把数据文件copy到hdfs不进行处理。
Hive推出的一种专门面向列的数据格式。
SequenceFile,RCFile格式的表不能直接从本地文件导入数据,数据要先导入到textfile格式的表中,然后再从textfile表中用insert导入到SequenceFile,RCFile表中。
TextFile和SequenceFile的存储格式都是基于行存储的,RCFile是基于行列混合的思想,先按行把数据分成N个row group,在row group中对每个列分别进行行存储。
Metastore:存储表,列好Partition等元数据,采用关系型数据库。
Driver:管理HiveQL执行的生命周期
-Compiler:编译HiveQL并将其转化为一些列相互依赖的Map/Reduce任务。
-Optimizer:优化器,分为逻辑优化器和物理优化器。
逻辑优化器:优化HiveQL生成的执行计划
物理优化器:优化MapReduce任务
-Executor:按照任务依赖关系执行MapReduce任务
Thrift Server:提供Thrift接口,作为jdbc和odbc的服务端,将hive与其他应用程序集成起来。
Clients:包含命令行接口(CLI)和JDBC/ODBC接口,为用户访问提供接口。
Web接口:用于监控和管理Hive的任务。
单用户模式
–此模式连接到一个 In-memory 的数据库 Derby ,一般用于 Unit Test
•多用户模式
–通过网络连接到一个数据库中,是最经常使用到的模式
•远程服务器模式
–用于非 Java 客户端访问元数据库,在服务器端启动MetaStoreServer,客户端利用Thrift 协议通过MetaStoreServer 访问元数据库