Spark Thrift Server 是一个jdbc和odbc服务,底层依赖的是hive Server2。
现在部分公司情况, 大数据部门更像是一个报表开发部门,日常工作就是开发报表,一个完了接着下一个。整个模式的架构如下: 关系数据库=》 大数据平台 =》关系数据库 =》报表后台 。
上面这种架构有一下几个问题。
1: 数据平台需要完成80%的计算指标,剩余部分由mysql完成,业务稍有变动数据平台也需要跟着调整。
2:业务的变更需要数据平台、报表后台开发的支持,导致不能够及时响应需求的变更。
3:也是最重要的一点,只开放了数据平台的人力,没有开放出计算平台的计算力(和人力成本比起来,硬件资源的成本很低)
上面的架构暴露出了问题,怎么去解决他那,这个时候Spark Thrift Server就排上用场了(如下图),通过它能够直接把集群的计算资源开放出去,后台开发通过调用jdbc服务来调用我们集群的计算资源。在底层我们只需开发出与业务相关最细粒度的事实表即可,不在需要去开发每一个具体的指标,数据的粒度没变,不论业务怎么变化,我们都不需要做调整。话不多说开始具体的实践吧
相关环境:CDH6.0.1, hive2.2.1 , Spark2.4.0(开源的)
1: 打通 Hive到Spark
把hive的hive-site.xml拷贝的${SPARK_HOME}/conf 里。
2:配置Spark Thrift Server2。
备注: 默认的Hive Server2服务端口是10000,注意重复
${SPARK_HOME}/conf/hive-site.xml
hive.server2.thrift.min.worker.threads
5
hive.server2.thrift.max.worker.threads
500
hive.server2.thrift.port
10001
hive.server2.thrift.bind.host
cdh102
./sbin/start-thriftserver.sh --master yarn --num-executors 2 \
–executor-cores 2
–conf “spark.executor.overhead.memory=1g”
–conf “spark.executor.memory=2g”
–jars ./mysql-connector-java-6.0.6.jar
服务的验证由好几个地方:
1:启动
$SPARK_HOME/bin/beeline
2:链接服务
!connect jdbc:hive2://cdh102:10001
输入对应的用户与密码:user:root, password:空。
3:查看链接后的状态
通过 http://hostname:4040验证,这里面还能查到每个sql具体的执行信息。
只需要开发jdbc程序就能够链接Spark SQL,代码如下
pom 依赖:
org.spark-project.hive
hive-jdbc
1.2.1.spark
org.apache.hadoop
hadoop-client
${hadoop.version}
public class SparkThriftDemo {
public static void main(String[] args) {
//add driver
String driver="org.apache.hive.jdbc.HiveDriver";
try {
Class.forName(driver);
//get connection
//这里的url就是启动beeline的时候用的url sid是hive中的库名
String jdbc="jdbc:hive2://cdh102:10001";
try {
Connection connection= DriverManager.getConnection(jdbc);
long startTime=System.currentTimeMillis(); //获取开始时间
//get statement
connection.prepareStatement("use game_dwd").execute();
String sql="select substr(a.ctime,0, 10) as day,substr(a.ctime,12, 2) as hour, a.barcode, a.activity_id , a.activity_name, count(distinct a.main_uid) as num from game_dwd.dwd_market_lottery a \n" +
"where substr(a.ctime,0, 10) < '2019-05-22' and substr(a.ctime,0, 10) > '2019-05-01'\n" +
"group by substr(a.ctime,0, 10), substr(a.ctime,12, 2), a.barcode, a.activity_id , a.activity_name ";
sql="select a.barcode , a.activity_id , a.activity_name, b.register_platform, substr(a.ctime,0, 10) as day, substr(a.ctime,12, 2) as hour, count(a.main_uid) as total_makets,sum(consume_circle) as num from game_dwd.dwd_market_lottery a \n" +
"join game_dwd.dwd_user_main b on a.main_uid = b.id\n" +
"GROUP BY a.barcode, b.register_platform , a.activity_id , a.activity_name,substr(a.ctime,0, 10) , substr(a.ctime,12, 2)";
Statement statement=connection.prepareStatement(sql);
//get result
ResultSet rs= statement.executeQuery(sql);
while(rs.next()){
System.out.println("day:"+ rs.getString("day") + " 抽奖人数:" + rs.getString("num"));
}
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(endTime-startTime
)+"ms");
rs.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
到了我们关心的效率问题了,一般我们关系的有两个问题,单次的查询耗时和并发耗时
1: 单次的情况如下, 这段sql是比较复杂,耗时约3秒 。 在这之上我们可以做优化,如存储格式
2:并发 由于一般这类报表都是面向运营和管理层的,用户量不大。如果到极端情况,我们可以增加Spark Thrift Server的个数,然后做负载均衡。
1:在写jdbc客服端的时候遇到了棘手的问题
原因是由于我的hive-jdbc版本不对,报了无连接的错,左后我拉去${SPARK_HOME}/jars 下对应的hive-jdbc 包就解决这个问题了。