spark内存计算框架
1.sparksql概述
1.1 sparksql的前世今生
- Shark是专门针对于spark的构建大规模数据仓库系统的一个框架
- Shark与Hive兼容、同时也依赖于Spark版本
- Hivesql底层把sql解析成了mapreduce程序,Shark是把sql语句解析成了Spark任务
- 随着性能优化的上限,以及集成SQL的一些复杂的分析功能,发现Hive的MapReduce思想限制了Shark的发展。
- 最后Databricks公司终止对Shark的开发
- 决定单独开发一个框架,不在依赖hive,把重点转移到了sparksql这个框架上。
1.2 什么是sparksql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fNbiE7fm-1599720421991)(图片/1569468946521.png)]
- Spark SQL is Apache Spark’s module for working with structured data.
- SparkSQL是apache Spark用来处理结构化数据的一个模块
10、spark on hive 与hive on spark
Spark on hive 与 Hive on Spark 的区别
- Spark on hive
Spark通过Spark-SQL使用hive 语句,操作hive,底层运行的还是 spark rdd。
(1)就是通过sparksql,加载hive的配置文件,获取到hive的元数据信息
(2)spark sql获取到hive的元数据信息之后就可以拿到hive的所有表的数据
(3)接下来就可以通过spark sql来操作hive表中的数据
- Hive on Spark
是把hive查询从mapreduce 的mr (Hadoop计算引擎)操作替换为spark rdd(spark 执行引擎) 操作. 相对于spark on hive,这个要实现起来则麻烦很多, 必须重新编译你的spark和导入jar包,不过目前大部分使用的是spark on hive。
1、spark_sql与hive进行整合
第一步:拷贝hive-site.xml配置文件
将node03服务器安装的hive家目录下的conf文件夹下面的hive-site.xml拷贝到spark安装的各个机器节点,node03执行以下命令进行拷贝
cd /kkb/install/hive-1.1.0-cdh5.14.2/conf
scp hive-site.xml node01:/kkb/install/spark-2.3.3-bin-hadoop2.7/conf/
scp hive-site.xml node02:/kkb/install/spark-2.3.3-bin-hadoop2.7/conf/
scp hive-site.xml node03:/kkb/install/spark-2.3.3-bin-hadoop2.7/conf/
第二步:拷贝mysql连接驱动包
将hive当中mysql的连接驱动包拷贝到spark安装家目录下的lib目录下,node03执行下命令拷贝mysql的lib驱动包
cd /kkb/install/hive-1.1.0-cdh5.14.2/lib/
scp mysql-connector-java-5.1.38.jar node01:/kkb/install/spark-2.3.3-bin-hadoop2.7/jars/
scp mysql-connector-java-5.1.38.jar node02:/kkb/install/spark-2.3.3-bin-hadoop2.7/jars/
scp mysql-connector-java-5.1.38.jar node03:/kkb/install/spark-2.3.3-bin-hadoop2.7/jars/
第三步:进入spark-sql直接操作hive数据库当中的数据
在spark2.0版本后由于出现了sparkSession,在初始化sqlContext的时候,会设置默认的spark.sql.warehouse.dir=spark-warehouse,
此时将hive与sparksql整合完成之后,在通过spark-sql脚本启动的时候,还是会在哪里启动spark-sql脚本,就会在当前目录下创建一个spark.sql.warehouse.dir为spark-warehouse的目录,存放由spark-sql创建数据库和创建表的数据信息,与之前hive的数据息不是放在同一个路径下(可以互相访问)。但是此时spark-sql中表的数据在本地,不利于操作,也不安全。
所有在启动的时候需要加上这样一个参数:
–conf spark.sql.warehouse.dir=hdfs://node01:8020/user/hive/warehouse
保证spark-sql启动时不在产生新的存放数据的目录,sparksql与hive最终使用的是hive同一存放数据的目录。
node01直接执行以下命令,进入spark-sql交互界面,然后操作hive当中的数据,
cd /kkb/install/spark-2.3.3-bin-hadoop2.7/
bin/spark-sql --master local[2] \
--executor-memory 512m --total-executor-cores 3 \
--conf spark.sql.warehouse.dir=hdfs://node01:8020/user/hive/warehouse \
--jars /kkb/install/hadoop-2.6.0-cdh5.14.2/share/hadoop/common/hadoop-lzo-0.4.20.jar
使用sparkSQL有hive进行整合之后,就可以通过sparkSQL语句来操作hive表数据了
- 应用场景
#!/bin/sh
#定义sparksql提交脚本的头信息
SUBMITINFO="spark-sql --master spark://node01:7077 --executor-memory 1g --total-executor-cores 4 --conf spark.sql.warehouse.dir=hdfs://node01:8020/user/hive/warehouse"
#定义一个sql语句
SQL="select * from default.hive_source;"
#执行sql语句 类似于 hive -e sql语句
echo "$SUBMITINFO"
echo "$SQL"
$SUBMITINFO -e "$SQL"
12、sparkSQL架构设计
sparkSQL是spark技术栈当中又一非常出彩的模块,通过引入SQL的支持,大大降低了开发人员和学习人员的使用成本,让我们开发人员直接使用SQL的方式就能够实现大数据的开发,它同时支持DSL以及SQL的语法风格,目前在spark的整个架构设计当中,所有的spark模块,例如SQL,SparkML,sparkGrahpx以及Structed Streaming等都是基于 Catalyst Optimization & Tungsten Execution模块之上运行,如下图所示就显示了spark的整体架构模块设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUBfUspn-1599720422013)(1%E3%80%81sparkSQL%E7%AC%AC%E4%BA%8C%E6%AC%A1%E8%AF%BE.assets/Untitled%20Diagram.png)]
1、sparkSQL的架构设计实现
sparkSQL 执行先会经过 SQL Parser 解析 SQL,然后经过 Catalyst 优化器处理,最后到 Spark 执行。而 Catalyst 的过程又分为很多个过程,其中包括:
- Analysis:主要利用 Catalog 信息将 Unresolved Logical Plan 解析成 Analyzed logical plan;
- Logical Optimizations:利用一些 Rule (规则)将 Analyzed logical plan 解析成 Optimized Logical Plan;
- Physical Planning:前面的 logical plan 不能被 Spark 执行,而这个过程是把 logical plan 转换成多个 physical plans,然后利用代价模型(cost model)选择最佳的 physical plan;
- Code Generation:这个过程会把 SQL 查询生成 Java 字 节码。
例如执行以下SQL语句:
select temp1.class,sum(temp1.degree),avg(temp1.degree) from (SELECT students.sno AS ssno,students.sname,students.ssex,students.sbirthday,students.class, scores.sno,scores.degree,scores.cno FROM students LEFT JOIN scores ON students.sno = scores.sno ) temp1 group by temp1.class
代码实现过程如下:
package com.kkb.sparksql
import java.util.Properties
import org.apache.spark.SparkConf
import org.apache.spark.sql.{
DataFrame, SparkSession}
//todo:利用sparksql加载mysql表中的数据
object DataFromMysqlPlan {
def main(args: Array[String]): Unit = {
//1、创建SparkConf对象
val sparkConf: SparkConf = new SparkConf().setAppName("DataFromMysql").setMaster("local[2]")
//sparkConf.set("spark.sql.codegen.wholeStage","true")
//2、创建SparkSession对象
val spark: SparkSession = SparkSession.builder().config(sparkConf).getOrCreate()
spark.sparkContext.setLogLevel("WARN")
//3、读取mysql表的数据
//3.1 指定mysql连接地址
val url="jdbc:mysql://localhost:3306/mydb?characterEncoding=UTF-8"
//3.2 指定要加载的表名
val student="students"
val score="scores"
// 3.3 配置连接数据库的相关属性
val properties = new Properties()
//用户名
properties.setProperty("user","root")
//密码
properties.setProperty("password","123456")
val studentFrame: DataFrame = spark.read.jdbc(url,student,properties)
val scoreFrame: DataFrame = spark.read.jdbc(url,score,properties)
//把dataFrame注册成表
studentFrame.createTempView("students")
scoreFrame.createOrReplaceTempView("scores")
//spark.sql("SELECT temp1.class,SUM(temp1.degree),AVG(temp1.degree) FROM (SELECT students.sno AS ssno,students.sname,students.ssex,students.sbirthday,students.class, scores.sno,scores.degree,scores.cno FROM students LEFT JOIN scores ON students.sno = scores.sno ) temp1 GROUP BY temp1.class; ").show()
val resultFrame: DataFrame = spark.sql("SELECT temp1.class,SUM(temp1.degree),AVG(temp1.degree) FROM (SELECT students.sno AS ssno,students.sname,students.ssex,students.sbirthday,students.class, scores.sno,scores.degree,scores.cno FROM students LEFT JOIN scores ON students.sno = scores.sno WHERE degree > 60 AND sbirthday > '1973-01-01 00:00:00' ) temp1 GROUP BY temp1.class")
resultFrame.explain(true)
resultFrame.show()
spark.stop()
}
}
通过explain方法来查看sql的执行计划,得到以下信息
== Parsed Logical Plan ==
'Aggregate ['temp1.class], ['temp1.class, unresolvedalias('SUM('temp1.degree), None), unresolvedalias('AVG('temp1.degree), None)]
+- 'SubqueryAlias temp1
+- 'Project ['students.sno AS ssno#16, 'students.sname, 'students.ssex, 'students.sbirthday, 'students.class, 'scores.sno, 'scores.degree, 'scores.cno]
+- 'Filter (('degree > 60) && ('sbirthday > 1973-01-01 00:00:00))
+- 'Join LeftOuter, ('students.sno = 'scores.sno)
:- 'UnresolvedRelation `students`
+- 'UnresolvedRelation `scores`
== Analyzed Logical Plan ==
class: string, sum(degree): decimal(20,1), avg(degree): decimal(14,5)
Aggregate [class#4], [class#4, sum(degree#12) AS sum(degree)#27, avg(degree#12) AS avg(degree)#28]
+- SubqueryAlias temp1
+- Project [sno#0 AS ssno#16, sname#1, ssex#2, sbirthday#3, class#4, sno#10, degree#12, cno#11]
+- Filter (