一、Spark 1.0版本之后,Spark官方推出了Spark SQL。其实最先使用的,都是Hadoop本身的Hive查询引擎;好比MR2,咱们底层都是运行的MR2模型,底层都是基于Hive的查询引擎。sql
二、后来Spark提供了Shark;再后来Shark被淘汰(Shark制约了Spark SQL的总体发展),推出了Spark SQL。Shark的性能比Hive就要高出一个数量级,而Spark SQL的性能又比Shark高出一个数量级。数据库
三、SparkSQL的前身是Shark,给熟悉RDBMS但又不理解MapReduce的技术人员提供快速上手的工具,Hive应运而生,它是当时惟一运行在Hadoop上的SQL-on-Hadoop工具。可是MapReduce计算过程当中大量的中间磁盘落地过程消耗了大量的I/O,下降的运行效率,为了提升SQL-on-Hadoop的效率,大量的SQL-on-Hadoop工具开始产生,其中表现较为突出的是:express
MapR的Drill Cloudera的Impala Shark
四、可是Hive有个致命的缺陷,就是它的底层基于MR2,而MR2的shuffle又是基于磁盘的,所以致使Hive的性能异常低下。常常出现复杂的SQL ETL,要运行数个小时,甚至数十个小时的状况。数组
五、Spark推出了Shark,Shark与Hive实际上仍是紧密关联的,Shark底层不少东西仍是依赖于Hive,可是修改了内存管理、物理计划、执行三个模块,底层使用Spark的基于内存的计算模型,从而让性能比Hive提高了数倍到上百倍。性能优化
一、可是,随着Spark的发展,对于野心勃勃的Spark团队来讲,Shark对于Hive的太多依赖(如采用Hive的语法解析器、查询优化器等等),制约了Spark的One Stack Rule Them All的既定方针,制约了Spark各个组件的相互集成,因此提出了SparkSQL项目。SparkSQL抛弃原有Shark的代码,汲取了Shark的一些优势,如内存列存储(In-Memory Columnar Storage)、Hive兼容性等,从新开发了SparkSQL代码;因为摆脱了对Hive的依赖性,SparkSQL不管在数据兼容、性能优化、组件扩展方面都获得了极大的方便,真可谓“退一步,海阔天空”。工具
二、Spark SQL的特色oop
1)、支持多种数据源:Hive、RDD、Parquet、JSON、JDBC等。性能
2)、多种性能优化技术:in-memory columnar storage、byte-code generation、cost model动态评估等。优化
3)、组件扩展性:对于SQL的语法解析器、分析器以及优化器,用户均可以本身从新开发,而且动态扩展。编码
数据兼容方面 不但兼容Hive,还能够从RDD、parquet文件、JSON文件中获取数据,将来版本甚至支持获取RDBMS数据以及cassandra等NOSQL数据;
性能优化方面 除了采起In-Memory Columnar Storage、byte-code generation等优化技术外、将会引进Cost Model对查询进行动态评估、获取最佳物理计划等等;
组件扩展方面 不管是SQL的语法解析器、分析器仍是优化器均可以从新定义,进行扩展。
2014年6月1日Shark项目和SparkSQL项目的主持人Reynold Xin宣布:中止对Shark的开发,团队将全部资源放SparkSQL项目上,至此,Shark的发展画上了句话,但也所以发展出两个直线:SparkSQL和Hive on Spark。
其中SparkSQL做为Spark生态的一员继续发展,而再也不受限于Hive,只是兼容Hive;而Hive on Spark是一个Hive的发展计划,该计划将Spark做为Hive的底层引擎之一,也就是说,Hive将再也不受限于一个引擎,能够采用Map-Reduce、Tez、Spark等引擎。
Shark的出现,使得SQL-on-Hadoop的性能比Hive有了10-100倍的提升:
那么,摆脱了Hive的限制,SparkSQL的性能又有怎么样的表现呢?虽然没有Shark相对于Hive那样瞩目地性能提高,但也表现得很是优异:
SparkSQL的表数据在内存中存储不是采用原生态的JVM对象存储方式,而是采用内存列存储,以下图所示:
一、该存储方式不管在空间占用量和读取吞吐率上都占有很大优点。
对于原生态的JVM对象存储方式,每一个对象一般要增长12-16字节的额外开销,对于一个270MB的数据,使用这种方式读入内存,要使用970MB左右的内存空间(一般是2~5倍于原生数据空间);另外,使用这种方式,每一个数据记录产生一个JVM对象,若是是大小为200B的数据记录,32G的堆栈将产生1.6亿个对象,这么多的对象,对于GC来讲,可能要消耗几分钟的时间来处理(JVM的垃圾收集时间与堆栈中的对象数量呈线性相关)。显然这种内存存储方式对于基于内存计算的Spark来讲,很昂贵也负担不起。
二、对于内存列存储来讲,将全部原生数据类型的列采用原生数组来存储,将Hive支持的复杂数据类型(如array、map等)先序化后并接成一个字节数组来存储。这样,每一个列建立一个JVM对象,从而致使能够快速的GC和紧凑的数据存储;额外的,还可使用低廉CPU开销的高效压缩方法(如字典编码、行长度编码等压缩方法)下降内存开销;更有趣的是,对于分析查询中频繁使用的聚合特定列,性能会获得很大的提升,缘由就是这些列的数据放在一块儿,更容易读入内存进行计算。
在数据库查询中有一个昂贵的操做是查询语句中的表达式,主要是因为JVM的内存模型引发的。
Spark SQL在其catalyst模块的expressions中增长了codegen模块,对于SQL语句中的计算表达式,好比select num + num from t这种的sql,就可使用动态字节码生成技术来优化其性能。
另外,SparkSQL在使用Scala编写代码的时候,尽可能避免低效的、容易GC的代码;尽管增长了编写代码的难度,但对于用户来讲,仍是使用统一的接口,没受到使用上的困难。