Kyuubi 在小米大数据平台的应用实践

语言: CN / TW / HK

分享嘉宾:张耀东 小米 高级研发工程师

出品平台:DataFunTalk

导读: 今天分享的主题是《Kyuubi 在小米大数据平台的应用实践》,主要分为四部分内容:

  • Kyuubi 在小米的落地过程 

  • 打造易用和高可用的 Kyuubi 服务 

  • 基于 kyuubi 的改进 

  • kyuubi的一些新特性在业务场景的应用

01

Kyuubi 在小米的落地过程

第一个主题:关于Kyuubi在小米的大数据平台落地过程和实施路径的分享。

1. 背景介绍

先介绍一下背景,小米的大数据体系在不断更新和迭代,随着业务架构、组织架构和技术架构的调整,内部大数据平台逐渐出现一些状况:

  • 出现了多个基于SQL的大数据平台服务,服务于各个业务部门,各自定位又有一定的差异,这样就给用户带来了困扰,到底选择哪个平台好,而且我们在用户支持的过程中发现,同一业务可能需要跨多个数据服务平台,流程繁琐。

  • 对于底层表资源的使用存在多套账号和权限体系:

a. MySQL/Doris: 系统的自有的 User&Password 认证和权限体系

b. Hive/Kudu基于 Kerberos 认证和 Sentry 的权限体系

c. Talos是基于小米内部平台组织和团队的认证与授权体系

  • 给用户使用和管理上带来了麻烦,没有统一的资源管理和权限管理视角,并且底层系统服务账号会直接暴露给用户,还会存在安全风险。

2. 构建一站式的大数据开发平台

上述现象直接导致了如下问题:

①对用户:

  • 多个平台和多体系给用户体验较差,开发数据流程长,不能快速上手。

  • 开发管理效率成本高,资源成本结算和任务管理没有统一的视图。

②对平台:

  • 各自的侧重点不同,都不能完全覆盖大数据场景下的能力需求,同时还有能力重复建设问题,导致资源浪费。

  • 出现问题排查和维护困难,需要堆人力解决。

面对数据平台难用的情况,提出了构建统一易用的大数据服务平台整体目标 。整体架构能力围绕数据链路解决方案、数仓解决方案、数据服务解决方案来进行建设,提供统一的元数据管理和权限管理体系。

在这个大背景和动机下,统一的数据入口服务成为了一个非常重要的能力,它主要解决:

  • 用户的易用性(一致的入口体验)

  • SQL流量治理(代理多引擎)

  • 数据访问的安全性管控(入口收敛和降低安全风险)

3. 小米SQL服务历史发展情况

从上面的背景问题中可以看到,小米内部有几套大数据处理的SQL服务入口,总体还是围绕经典的SQL On Hadoop架构体系来构建,逐步从ThriftServer演进到向上抽象一层的SQL Proxy服务,在底层集成了Hive/Spark/Doris等引擎为ETL作业、Ad-Hoc查询提供支持。

抽离的SparkThriftServer的实现模块作为独立的SQL Proxy服务,提供:

  • ETL 场景下的HiveServer和Spark APP代理(非常驻)

  • Ad-Hoc 场景下的STS、Kylin、Druid代理

从这里可以看到SQL Proxy和Kyuubi Server的定位非常相似,但是存在很多不足:

a. SQL Proxy 没有完全剥离STS的实现,通过反射的方式进行复用,代码耦合很高,依赖Spark特定版本,升级困难

b. 底层引擎代理层没有统一抽象,与其他引擎适配困难,对底层引擎扩展性差

c. 无法本地调试,依赖hadoop配置,在办公和服务环境网络隔离情况下,必须在开发机上完成完整的功能测试和调试,开发和部署路径长

4. 基于Kyuubi 构建统一SQL入口

(1) 为什么选择Kyuubi

通过上面的分析,我们发现在业务和架构上都存在着一些问题需要解决。

① 业务上:

  • 在重新打造统一的大数据体系的推动下,构建统一的SQL入口服务势在必行。

  • 需要更快的分析引擎,这里我们选择了Trino。

  • 一套易用、高可用并可以持续演进的服务架构,提升大数据研发的生产力。

SQLProxy架构需要升级:

  • 完全兼容HiveThrift协议。

  • 松耦合的实现,基于STS实现的完全剥离。

  • 灵活可扩展的代理多引擎的适配。

Kyuubi的优势在于:

  • 与STS和HS2的完全兼容一致

  • 高可用和资源隔离

  • 清晰简洁的架构,可测试、可维护、可扩展

  • 社区高质量实现和业界生产环境大量运用

SQLProxy和Kyuubi的架构非常相似,切换成本低。在业务需求和架构升级的双重推动下,我们选择了Kyuubi。

(2)架构升级

升级过程和效果与我们的预期一致,可以看到架构相比SQLProxy更加简洁,扩展底层引擎非常容易,而且本地可测试可调试,极大提升了开发效率。 从开发到上线新架构两周时间就完成了平滑迁移。

升级新架构带来的效果也非常明显,相比之前的架构不论代码质量、服务稳定性、可维护性和可扩展性上都有了重大提升:

  • 多引擎的代理能力(主要支持Spark/Trino/Hive/Doris)。

  • 基于数据平台workspace的体系在Kyuubi Server端实现了权限验证和资源隔离。

  • 更加规范化的Hive Thrift API支持,各种生态可视化工具(Redash/Datagrip等)完美兼容。

(3) 统一SQL服务的现状

经过半年的迁移推动,每日SQL有效处理量从5W提升到现在的50W规模,已经占据了整个SQL流量的80%。 特别是SparkSQL的流量半年新增到30W。 大体流量分布: Spark 36w/ Trino 12w / Hive 2.5w

各个引擎请求耗时:

  • Spark和Trino持平,平均延时30秒左右,P50在5秒左右

  • Hive的执行效率明显低于以上两个引擎,跟Hive的大任务有关,ETL偏多

目前Kyuubi Server 承载真实的SQL流量日均100w左右,可用性仍然可达99.9%以上,非常稳定。

02 

打造易用易维护高可用的Kyuubi服务

1. 构建符合业务需求的Kyuubi

(1) 整体架构

整体架构和流程,主要分为入口服务、认证和权限适配、底层引擎管理及服务的可观测性:

  • Kyuubi Server为基础构建了SQL 统一入口服务 

  • Kyuubi Engine 作为Spark SQL执行引擎层 

  • 独立Engine Manager服务管理各类计算引擎

  • Kyuubi Server层集成Ranger服务,支持基于数据平台的统一权限验证

  • 扩展适配Trino/Hive/Doris引擎服务指标和审计日志的可视化

(2) 用户使用交互

以工作空间(workspace)粒度来保计算资源的隔离的存储资源(表)安全,与Kyuubi Group 的多租户类似,我们这里扩展到了其他引擎。

一次完成交互过程:

WorkspaceA下面的用户使用平台发放的Token,选择各类客户端工具,向引擎提交SQL查询,Kyuubi Server会自动将用户SQL提交到该空间所属的计算引擎上去,来保证用户使用资源的隔离性。与其他workspace用户虽是同一入口,但是资源的使用上是隔离的。

Kyuubi Server服务并不具体执行SQL,同一的入口服务不会有太大压力。

2. 提升用户侧的易用性

(1) 统一认证和表坐标的统一

去Kerberos化,采用平台统一Token方式,解决:

  • Kerberos接入流程繁琐

  • 普通用户对kerberos机制难以理解,出现问题排查困难

  • 用户管理不当,同一账号下用户膨胀问题

  • 审计和追踪不能精确定位到用户个人

表资源命名的统一规范化,小米内部存在多区域和多类数据源,如果使用统一的SQL入口服务, 需要统一SQL语句的表名规范来避免冲突和统一的管理:

  • 采用Catalog.Schema.Table 三级表名为唯一表名

  • Kyuubi Server端支持JDBC URL预设Catalog/Schema,兼容之前SQL中二级或者一级表名

  • 结合URL和SQL Table生成完整的三级表坐标,以供用户权限认证

(2) Kyuubi Engine 公共资源池

引入Kyuubi Engine公共池主要解决用户首次进入空间提交SparkSQL的查询性能问题。 上面提到的用户提交的SQL分析统计,50%的SQL查询延时都在5秒以下。 在没有提前分配的资源的情况下,用户提交查询会冷启动一个Kyuubi Engine,这是Kyuubi当前的机制。 由于小米Yarn提交一个APP的延时在分钟级别,用户一个简单的秒级查询会延迟到分钟级别,体感非常差。

因此,借助Kyuubi Engine Pool的实现,对没有提前配置和指定资源的workspace用户,会将SQL路由到已经预先启动好的Kyuubi Engine Pool,以加快用户的查询速度,提升SQL查询体验。

3. 升级Spark2.X到Kyuubi Engine

Kyuubi Engine目前只支持Spark3以上,之前我们内部版本都是Spark2,在升级到Kyuubi Engine之前做了相关对比测试,在Kyuubi 架构和SQLProxy架构下,有明显的性能提升:

  • 在TPC-DS标准测试集上,P50延时有75%的性能提升,长尾基本和SQLProxy性能持平。

  • 在真实的业务场景下,P50延时也有37%的性能提升,长尾也基本跟SQLProxy一致,也就是升级的Kyuubi Engine的性能在多数情况下要优于Spark2,整体上不会比Spark2更差。

4. Kyuubi Server的容器化

在Kyuubi Server的高可用上利用容器化的方式替换了当前Kyuubi Client端通过ZK进行服务发现的高可用模式:

  • 在K8s上部署Kyuubi Server服务,充分利用K8s的弹性能力保障高可用。

  • Kyuubi Server和Kyuubi Engine的部署彻底解耦,作为一个单独的Thrift RPC代理服务和HTTP服务,去除Hadoop相关的配置环境依赖,和普通业务服务一样使用LVS做流量负载均衡。

  • 同时借助内部K8s平台的CI/CD能力,实现了Kyuubi Server服务的全自动灰度发布,支持一键升级和扩缩容。

5. 基于Workspace的计算资源管理

(1)Engine Manager

由于之前已经实现了对Spark Engine的管理服务,我们将Kyuubi Engine的管理直接从Kyuubi Server剥离,形成了单独的Engine Manager服务,负责Engine的生命周期管理,配置上下文管理,同时提供服务发现和负载均衡能力。

  • 为管理入口提供引擎配置和生命周期管理。

  • 为Kyuubi Server提供SQL路由的能力。

  • 为运维提供可视化的监控能力,包括Engine的服务状态、资源占用以及繁忙程度等,便于快速运维。

用户提交的SQL的流程:

  • 首先经过Kyuubi Server入口的认证和权限验证。

  • Kyuubi Server向EngineManager可用的Kyuubi Engine地址。

  • EngineManager 向ZK获取当前用户空间下可用的Engine,然后统计当前可用Engine的繁忙指标,返回相对空闲的Engine给Kyuubi Server。

  • Kyuubi Server 将SQL提交到EngineManager建议的Engine上去执行。

(2) 用户提交

图上是我们的用户平台SQL查询入口,在workspace下的用户可以非常方便地启动一个Kyuubi Engine。为降低用户的门槛,只暴露了资源相关和排队策略的配置。同时,用户还可以配置多个Kyuubi Engine实例,来保障当前workspace下的SQL执行的高可用。

(3) Engine的高可用

为什么需要Kyuubi Engine的高可用? 因为在实际环境中,Kyuubi Engine是一直长时间运行的,Spark的SQL执行过程非常复杂,时间一长其稳定性就有了问题:

  • 开启动态资源策略后丢事件的Bug,导致资源无法释放。

  • 大任务占用时间长,可能阻塞一些小任务的运行。

  • Driver端JVM Full GC时间过长和OOM。

  • SQL不合理导致的Engine频繁重启。

因此实施了一些高可用的保障策略:

  • workspace级别隔离Engine异常,避免影响其他用户。

  • 观测Engine 可用指标,通过繁忙和探活信息标记是否当前可用。

  • 同一workspace下多个Engine实例(Kyuubi 的Engine Pool机制),提升整体可用性,同时提供基于负载的分发。

  • 发现异常及时自动重启。

  • 频繁重启Engine通过告警机制,人工及时介入。

03

基于Kyuubi的改造

1. Trino和Doris的代理

引入Trino和Doris主要解决OLAP场景的查询效率问题。

  • Kyuubi 在1.1.0版本还未支持Trino,我们在kyuubi Server端使用Trino-JDBC完成了对Trino引擎的适配。

  • Trino-JDBC实现了流迭代器的模式,每次nextResult都会触发一次对Trino 引擎的请求。

  • 当前社区Trino-Client实现,会一次性的拉取所有结果集可能导致OOM的风险。

对于Doris的适配也采用了JDBC的方式,由于Doris客户端本身支持Mysql JDBC,MySQL JDBC的实现方式是全量拉取模式,Kyuubi Server端有OOM的风险。目前通过限制Doris查询的超时时间来降低大结果集导致OOM的风险。

如果大家后面要扩展Kyuubi代理其他JDBC的数据库支持,一定谨慎处理。

2. SQL HTTP API的支持

关于HTTP API的支持一共实现了V1版本和V2版本,相比社区还是有一些区别。

① V1版本

  • 简化用户的交互过程,简化Hive Thrift RPC的调用流程,用户直接在上层应用程序中通过HTTP 请求就能提交SQL,对一些研发用户来说是非常友好的。提交SQL根据QueryID,不断轮询获取结果。

  • 复用了Thrift backend Service的实现,水平扩展了一层HTTP Fronted Service。 底层实现跟Thrift API完全保持一致。

但是也存在一些问题:

  • Kyuubi Service端是有Session状态的,Step1和Step2必须路由的同一个实例才能获取到结果,采用IP Hash不能完全解决。

  • 这样也导致Kyuubi Server HTTP 服务无法水平扩展和平滑升级。

②V2版本

为了彻底解决V1的水平扩展性问题,在V2版本中将Kyuubi HTTP Server完全无状态化,通过Kyuubi Engine 直接提供HTTP SQL API。Kyuubi Server只起到出代理的作用。

另外的两点改进:

  • 彻底解决大结果集的导致Kyuubi Engine OOM的问题,将查询类的结果直接持久化到HDFS,不经过Spark Driver端。

  • 户在获取结果的时候不经过Kyuubi Engine,直接从HDFS层流式获取结果集。

同时,也不用维持长链接,非常适合ETL的场景。

3. SQL 表列解析

我们在Kyuubi Server端做了权限认证,需要获取用户SQL的真实表名,单独开发了一个纯SQL的解析模块:支持表列血缘关系和SQL类型的提取,支持SparkSQL、Trino两种语法。

具体解析后的格式如图,包括类型、输入输出表和队列的列。

后续在具体实际场景中该模块的也应用到了其业务场景,比如表血缘审计日志,SQL的统计请求分析等安全质量场景,完全复用了我们的SQL表列提取的能力。

04

Kyuubi 新特性的应用 

1. 小文件合并

解决用户写场景可能导致的小文件过多的问题。 用户一般会提交两个SQL: 一个是业务处理SQL,一个是合并SQL,通过通过workflow方式串联起来,维护不变。

开启也非常简单,可以在Kyuubi Engine启动阶段,SQL提交阶段开启开关。

2. 增量获取和获取结果集限制

  • 主要是JDBC下用户有结果集的查询导致的OOM问题,开启增量模式。但有些场景下会有部分分区的结果太大,导致取结果过程阻塞,导致有不好的用户体验。推荐采用HTTP API 异步结果获取方式解决。

  • 对用户一些预览数据的SQL,如果访问的表非常大,限制查询条数输出是一个非常好的功能,避免不必要的开销

3. Z-Ordering

在我们内部画像场景做相关的测试,Z-Ordering有显著的提升。

  • 业务查询时间

  • 存储空间

  • 查询扫描数据量

  • 文件数量

在具体应用中,Z-Ordering的排序规则需要根据实际业务表的数据做相应调整:

  • 我们画像场景查询频次高的列进行排序,效果明显

  • 超过3个列后的优化并不理想

  • 排序列应选择基数较大且没有倾斜的列

Kyuubi Engine Z-Ordering的实现非常巧妙,没有增加额外的列,直接复用了parquet的原生能力,所以一次生成可以支持多个引擎查询(只要该引擎支持parequet格式的读取)。

4. PlanOnly 模式

主要用于非SQL执行的SQL相关场景,比如:

  • 为数据平台提供语法语义校验服务

  • SQL 提交前的检查

  • SQL 语法语义兼容性的检查(Spark2.X->Spark3.X的升级)

PlanOnly模式下SQL不会真正执行,只会输出解析后的LogicalPlan/SparkPlan。目前为数据平台单独提供了语法语义校验服务,就是采用Kyuubi Engine的PlanOnly模式。

这种应用场景也为我们提供了一种新思路:将Kyuubi Engine作为Yarn APP的服务框架,提供其他场景的服务,比如校验服务、血缘关系提取服务和SQL的预计算服务等。

5. Scala mode

Scala Code模式完全解放了Kyuubi Engine能力,具备直接通过JDBC提交Scala 代码的能力,专门处理一些复杂逻辑的业务。

目前我们的应用场景在运维这块做了一些尝试,主要解决我们的运维效率。例如我们要在运行时动态加载用户自定义的jar包,读取Thrift格式化的数据。相比之前登录到生产集群机器打包代码运行的流程大大简化。

05

未来规划和总结

规划:

  • 基于业务场景、SQL规则和执行代价事前预测,实现多引擎下的自动路由能力。

  • HTTP API代替Thrift API提交的ETL作业,异步化取代长连接的方式。

总结:

  • Kyuubi 是非常优秀开源实践,已经成为小米内部大 数据服务入口的重要基础架构服务 。

  • 常感谢Kyuubi的社区的贡献,加速了我们统一 SQL服务的落地 。

  • 信未来Kyuubi会成为大数据场景下的SQL Gateway标杆,与大家一起共建Kyuubi生态 。

今天的分享就到这里,谢谢大家。

在文末分享、点赞、在看,给个3连击呗~

01 / 分享嘉宾