1)小文件合并
Hive SQL可以通过设置以下配置合并小文件,MR Job结束后,判断生成文件的平均大小,如果小于阀值,就再启动一个Job来合并文件。
目前Spark SQL不支持小文件合并,在迁移过程中,我们经常发现Spark SQL生成的文件数多于Hive SQL,为此我们参考Hive SQL的实现在Spark SQL中引入了小文件合并功能。
在InsertIntoHiveTable 中判断如果开启小文件合并,并且文件的平均大小低于阈值则执行合并,合并之后再执行loadTable或者loadPartition操作。
2)Spark SQL支持Cluster模式
Hive SQL任务是DataStudio通过beeline -f执行的,客户端只负责发送SQL语句给HS2,已经获取执行结果,因此是非常轻量的。而Spark SQL只支持Client模式,Driver在Client进程中,因此Client模式执行Spark SQL时,有时会占用很多的资源,DataStudio无法感知Spark Driver的资源开销,所以在DataStudio层面会带来以下问题:
- 形成资源热点,影响任务执行;
- 随着迁移到Spark SQL的任务越来越多,DataStudio需要越来越多的机器调度SQL任务;
- Client模式日志保留在本地,排查问题时不方便看日志;
所以我们开发了Spark SQL支持Cluster模式,该模式只支持非交互式方式执行SQL,包括spark-sql -e和spark-sql -f,不支持交互式模式。
3)分区剪裁优化
迁移过程中我们发现大部分任务的分区条件包括concat, concat_ws, substr等UDF, HiveServer2会调用MetaStore的getPartitionsByExpr方法返回符合分区条件的有效分区,避免无效的扫描, 但是Spark SQL的分区剪裁只支持由Attribute和Literal组成key/value结构的谓词条件,这一方面导致无法有效分区剪裁,会查询所有分区的数据, 造成读取大量无效数据,另一方面查询所有分区的元数据,导致MetaStore对MySQL查询压力激增,导致mysql进程把cpu打满。我们在社区版本的基础上迭代支持了多种场景的分区联合剪裁,目前能够覆盖生产任务90%以上的场景。
- concat/concat_ws联合剪裁场景
- substr 联合剪裁场景
- concat/concat_ws&substr组合场景
目前已经反馈社区,正在讨论中,具体可参考[SPARK-33707][SQL] Support multiple types of function partition pruning on hive metastore