通过Thrift Server使用JDBC来运行Spark SQL
标签(空格分隔): thriftserver jdbc sparkSQL
更新记录
初始发布:2017-09-19
第一次更新:xxx
简介
Thrift JDBC/ODBC Server (简称 Spark Thrift Server 或者 STS)是Spark SQL的Apache Hive HiveServer2的端口,通过这个端口可以允许用户使用JDBC/ODBC端口协议来执行SQL查询。
通过使用STS,商业用户就可以用使用一些炫目的BI工具,比如Tableau来连接Spark进行基于大数据量的报表制作。
开启与关闭服务
STS是Spark的一个独立应用,可以通过 start-thriftserver.sh 开启, stop-thriftserver.sh来关闭。
启动命令
sh $SPARK_HOME/sbin/start-thriftserver.sh
当修改了配置的时候,需要使用这个命令重启一些服务。
一些启动参数
sh $SPARK_HOME/sbin/start-thriftserver.sh \
--hiveconf hive.server2.thrift.port=10000 \
--master MASTER_URL \ //master的URL,如spark://host:port, mesos://host:port, yarn, 或local
--queue queue_name \ //如果使用yarn模式,设置队列名字
--num-executors NUM \ //executor的数目
--conf spark.driver.memory=40g \ //driver内存的大小
--driver-cores NUM \ //driver CPU数目,cluster模式才有这个参数
--executor-memory 6g \ //executor内存大小,如果开启动态分配,这个就不需要了
--conf spark.yarn.executor.memoryOverhead=2048 \ //overhead大小
一些tips
1.ResultSize问题
driver内存问题,在有些场景下,需要把结果集拉到driver端,默认的结果集大小为1G,如果超过了这个数字,则会报错,需要设置对应的参数,如
--conf spark.driver.maxResultSize=10G
2.driver与executor32G内存问题导致的截断(https://issues.apache.org/jira/browse/SPARK-10914)
影响版本:1.5.0, 1.5.1
修复版本:1.5.2, 1.6.0
在一次关联任务中发现,在hive中可以关联的SQL任务,在SparkSQL中结果为空,查询几条数据发现,部分结果被截断,显示为乱码。经查,发现是指针压缩问题,当内存小于32G的时候不存在问题,而大约32G的时候存在问题,由于我们设置的driver内存为40G超过了32G,所以该问题凸显,网上其他用户反馈,executor同样面临这个问题。
临时解决办法,添加下面两个配置:
-conf "spark.executor.extraJavaOptions=-XX:-UseCompressedOops" --driver-java-options "-XX:-UseCompressedOops"
3.thriftserver内存泄露问题(https://issues.apache.org/jira/browse/SPARK-14261)
影响版本:1.6.0
修复版本:1.6.2, 2.0.0
经查,该问题由HiveConf无法进行内存释放导致,随着SQL任务提交越来越小,真正可用内存会越来越少,导致thriftserver无法有效响应任务直至死亡。目前没有有效解决办法,只有升级到Spark1.6.2,经过目前的实践,建议使用该版本。
4.Spark2.x的CATS问题(参考我的原来的博客:http://blog.csdn.net/bon_mot/article/details/75256525)
影响版本:2.1.1, 2.2.0
修复版本:None
我们知道在使用SparkSQL通过查询创建表是最常使用的场景,但是这个功能存在致命bug,目前还没有修复,建议不要轻易尝试使用。
5.使用密码验证
参考这篇文章:https://ieevee.com/tech/2016/05/18/spark-9-sts-auth.html
启动的时候加上这个参数就可以了。
--jars $SPARK_HOME/lib/sparkAuth.jar
6.GC问题
SparkSQL有时候会出现GC问题,这个时候可以适当考虑减少RDD缓存,降低spark.storage.memoryFraction的比例。但最重要的其实是解决SQL写法的问题,注意做好预处理再进行关联,避免重复扫描一些数据,也避免扫描不真正使用的数据。
7.group by与文件数目过多的导致的full GC
当文件数目特别多,且关联的对象文件数目也很多的时候,这个时候做聚合分析,很容易出现严重的GC问题。做法是分步骤实现,关联小表的文件数目不要太多,主表先做预处理,加上distribute by rand()
把文件数目先降下来。例子如下:
create table test_temp_20170912001 as
select t1.*, t2.*
from test1 t1
inner join test2 t2
on t1.id = yt.id
and t2.site in ('site1','site2','site3','site4')
where t1.acct_month in (201706, 201707,201708)
distribute by rand();
该例子上原本test1每个月文件数目默认是600个,三个月就是1800个,再关联test2,文件数目可达数千个。而使用了distribute by rand()
,文件数目会变成默认的200个。原本可能无法跑过去的任务,可能几十秒就搞定了。
8.临时表关联写到where条件中
有的时候使用临时表再去做关联,不如直接写到where条件中,因为这个相当于对变量做了广播,性能会大幅度提升。
9.增加广播变量
可以增加广播变量参数,设置广播变量阈值。这个可以配置参数如下:
--conf spark.broadcast.compress=true \
--conf spark.sql.autoBroadcastJoinThreshold=104857600 \
但是这个奇怪的是,好像没有生效,可能是小表过大,超过了100M,分析解决中。
10.Parquet存储压缩(待解决)
通过使用Parquet存储,性能能够得到一定程度的提升,但是Parquet产生的结果目前来说压缩存在的一定的问题,insert数据无法使用snappy压缩,解决中。
设置下面的参数,sparkSQL不真正使用下面的参数:
TBLPROPERTIES (
'Compressed'='true',
'parquet.compression'='SNAPPY'
已经测试过,可以排除这个问题。
11.KyroSerializer
序列化的时候需要加上下面的参数,避免出现buffer空间不足溢出的情况。
--conf spark.kryoserializer.buffer.max=256m \
--conf spark.kryoserializer.buffer=64m \
12.使用hive表问题
有时候使用hive生成的中间表会导致程序不能正常响应,会报错,可能是catalyst语法解析上出现了问题。暂时没有找到具体原因,出问题了可以从这个思路排查一下。具体错误可能如下:
task error:java.sql.SQLException: org.apache.spark.sql.catalyst.errors.package$TreeNodeException: execute, tree:
13.动态资源分配
可以使用spark自身的动态资源分配参数,参考http://lxw1234.com/archives/2015/12/593.htm
以yarn-client模式启动ThriftServer:
cd $SPARK_HOME/sbin/
./start-thriftserver.sh \
--master yarn-client \
--conf spark.driver.memory=3G \
--conf spark.shuffle.service.enabled=true \
--conf spark.dynamicAllocation.enabled=true \
--conf spark.dynamicAllocation.minExecutors=1 \
--conf spark.dynamicAllocation.maxExecutors=30 \
--conf spark.dynamicAllocation.sustainedSchedulerBacklogTimeout=5s
启动后,ThriftServer会在Yarn上作为一个长服务来运行。
14.部分场合使用left semi join代替inner join
left semi join
会自动进行广播变量,性能会大幅度提升,在某些场景下替代inner join
,性能会有质的飞跃,值得尝试。它的产生动机是:对于reduce side join,跨机器的数据传输量非常大,这成了join操作的一个瓶颈,如果能够在map端过滤掉不会参加join操作的数据,则可以大大节省网络IO,提升执行效率。
但是要注意left semi join和inner join还是有区别的,一定要搞清楚这一块:
- left semi join 子句中右边的表只能在 ON 子句中设置过滤条件,在 WHERE 子句、SELECT
子句或其他地方过滤都不行。 - 对待右表中重复key的处理方式差异:因为 left semi join 是 in(keySet)的关系,遇到右表重复记录,左表会跳过,而join on 则会一直遍历。