1. 现状
1.Kyuubi是一个基于Spark提供多租户、Serverless SQL 服务的组件,使用kyuubi提交作业实际是一个spark 作业。简单来说,Kyuubi的使用的场景类似是Spark SQL,但是Kyuubi支持不同租户,不同级别的引擎共享。在Kyuubi的配置中,提供的 kyuubi.engine.share.level 配置,可以定义 Kyuubi 服务的引擎共享级别
共享级别 | 含义 | 备注 |
---|---|---|
CONNECTION | 每个 Session 独占一个引擎 | 每个连接首次建立时,带来较大的引擎创建开销。 |
USER | 每个用户独占一个引擎 | 开箱配置。 |
GROUP | 每个资源组使用一个引擎 | |
SERVER | 每个集群使用一个引擎 | 隔离级别最低,需要管理员对集群安全性有足够把握。 |
根据官方配置,Kyuubi默认配置的是USER级别的引擎共享,这说明一个用户如果已经创建了一个计算引擎,在这个计算引擎存活的时间范围内,这个用户再提交的作业都会复用这个计算引擎,这里可以简单理解为底层复用同一个Spark上下文和计算资源。包括,队列、提交模式、application_id等信息。
2. 复现
首先在hive里准备了三个库,每个库里有一个表对应关系如下:
库名 | 表名 |
---|---|
test_kyuubi | t_user |
test_kyuubi2 | t2_user |
test_kyuubi3 | t3_user |
这三个表的字段都是一样的,包括id和username。
create database <databaseName>;
create table <tablename>(id int, username string)ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
首先,使用spark-sql提交一个spark作业,这个sql就插入一条数据进到test_kyuubi
insert into test_kyuubi.t_user value (1, "u1");
可以看到,我们得到一个application_id,登录spark history ui,可以看见详情
再次提交一个
insert into test_kyuubi.t_user value (2, "u2");
综上可以看出。对于Spark sql来说每次提交一个sql,都是一个新的spark作业。spark会重新生成一个Spark上下文然后申请资源,计算等。
使用kyuubi来提交同样的作业,这次使用test_kyuubi2.t2_user
insert into test_kyuubi2.t2_user value (1, "u1");
可以看出,第一次提交需要的创建一些Spark 的上下文和资源分配,这个作业在15:25结束了。再次提交一个
insert into test_kyuubi2.t2_user value (2, "u2");
可以看出,第二次没有创建Spark 上下文,申请资源这些过程,而是直接执行了作业,且和上一个SQL作业是用了同一个application_id。这个作业结束的很快。看一下spark history ui
这个spark 作业还是没结束的。要等到这个计算引擎失活,这个application_id才会结束。这就意味着,在某些条件下,对于诊断系统来说,这个spark 作业就是一个常驻作业,基本上不会结束。用户的每次提交都会转换成这个作业的job。
2. 问题
现在spark作业诊断来说,问题有以下几点:
- 作业没结束,影响资源浪费这种需要运行时间的诊断,有可能还是一个常驻作业
- 用户提交的sql和job不是一一对应的,对于某些复杂的SQL可能会拆分成多个job,两个作业之间没有界限,这就会导致诊断的时候都混在一起
3. 解决
如果想要每次提交都是一个单独的spark作业,一种是修改kyuubi的配置,改为session级别的,另一种是在连接串中加入#kyuubi.engine.share.level.subdomain=XXX这个配置,这样如果XXX每次是不同的,kyuubi就会去创建不同的计算引擎,注意要配置引擎失活时间,防止资源浪费。