分享嘉宾:姚琴 网易数帆 技术专家
洪冬冬 中国移动云能力中心 软件开发工程师
编辑整理:牛红艳
出品平台:DataFunTalk
导读:在云原生+大数据的时代,随着业务数据量的爆炸式增长以及对高时效性的要求,云原生大数据分析技术,经历了从传统数仓到数据湖,再到湖仓一体的演进。本文主要介绍Apache Kyuubi技术架构,及 Kyuubi在移动云的应用场景。
今天的介绍会围绕下面五点展开:
- Kyuubi系统简介
- Kyuubi架构解析
- Kyuubi使用场景
- Kyuubi开放社区
- Kyuubi在移动云的实践
Kyuubi系统简介
首先,让我们来认识一下 Kyuubi。
Kyuubi 的中文译名是“九尾狐”,狐会喷火,用来致敬 Apache Spark,九代表多租户能力,最后的BI揭示我们最初面向的是大数据的BI场景。所以我们的图标是一只狐狸。
Kyuubi 是一个 Thrift JDBC/ODBC 服务,目前对接了 Apache Spark 计算框架,支持多租户和分布式等特性,可以满足企业内诸如 ETL、BI 报表等多种大数据场景的应用。
Kyuubi 的服务层提供JDBC等标准化的接口,隐藏底层计算框架、存储系统,开箱即用,用户无需编写和配置 Spark 程序,大大降低用户使用门槛。
我们通过 Kyuubi 的引擎层封装完整的 Spark SQL 能力,提供高性能的大数据分析处理能力。首先,它可以Run anywhere,既可以支持跑在传统的 YARN 集群上,也支持 K8s 集群;其次,通过 Spark SQL DataSource API 的强大能力,可以让我们轻松的将传统大数据数仓和数据湖框架串联起来,构建湖仓一体。最后,通过服务化,SQL 化的方式提供大数据处理能力,也可以大大提升底层开发运维同学的工作效率。一方面可以更加方便的去诊断和调优,另一方面可以做充分的鉴权认证,保证数据安全,也可以简化部署、升级等日常运维工作。
所以,从现阶段的核心能力来说,Kyuubi 提供了一个兼容 HiveServer2 协议的接口,加上在Spark SQL 之上构建多租户、多应用服务的能力,可以让用户以“服务化”的方式运行 Spark 的各种数据计算任务。
从社区当前阶段的发展目标来看,它的主要方向是依托本身的架构设计,围绕各类主流计算框架,打造一个面向 Serverless SQL on Lakehouse 的服务,支持更加丰富的大数据场景应用。在接入侧,社区除了完整的对接了传统 Hive 数仓生态,也在尝试提供REST API 和 MySQL 协议的支持。在计算侧,也在尝试对 Flink 、Presto 等计算框架的支持。在存储侧,我们也对所有的数据湖框架完成了支持。大家可以前往我们的 Github 地址进一步了解社区的动态。
Kyuubi架构解析
接下来,介绍 Kyuubi 的实现架构。
在这之前,我们先来看看 Spark Thrift Server 的实现和存在的问题。从狭义的角度来讲,我们可以认为 Kyuubi 是 Spark Thrift Server 的增强版本。在易用性上,Spark 社区一路用 RDD 替换Map Reduce,简化了大数据编程逻辑,接着又上了 Data Frame 来屏蔽了 RDD 的底层细节,进一步降低编程难度,而 Thrift Server 的出现则进一步让它变得“开箱即用”, 用户无需 Spark 编程基础,直接用 SQL 就可以进行交互式数据分析。
但是,它在带来便利的同时,不足之处也是比较明显的。
- 首先,它是“服务”于“计算引擎”完全耦合的“单”应用。它响应客户端Session 和 Operation 等请求,完成对SparkSession 实例的新建及SQL API的调用,然后所有的计算调度交给一个 SparkContext 单例来完成。单应用导致了它只能在使用单条队列的资源,无法通过YARN、K8s这类资源管理器做资源隔离。这与我们线上普遍为不同的产品线或者团队划分不同队列是大相径庭的。同时它只有一个 Spark Driver,负责所有的 SQL 编译,DAG 调度,容易过载,任务之间很容易相互影响。
- 一个Spark 应用只有一个全局的用户,所以它本质上是一个单租户系统,对于一些数据安全级别比较高的场景,它并不适配。
- 此外,作为一个“常驻”的服务,没有“高可用”的支持导致了它客户端并发能力受限,且容易造成单点故障,不适用于大规模的生产落地。
为了突破 Spark Thrift Server 架构上的限制,实现“服务”与“计算引擎”的解耦,并引入多租户及高可用等能力,我们引入了常驻的 KyuubiServer进程,可定义生命周期的Kyuubi引擎,及两层的服务发现模块。Kyuubi引擎的实现逻辑和 Spark Thrift Server 如出一辙,不同的是它可以通过client/cluster模式提交,IP和端口都是随机的,所以额外加上了做服务发现的客户端,用于将自己暴露给Server和对应的租户。KyuubiServer本质上也共用了引擎的设计和抽象。在具体的实现上,针对连接请求,我们在 Server 端裂变成了两类操作,一个是引擎类型的操作,包括发现逻辑和新建逻辑,这为多应用提供了基础。另一个 Session 本身的连接逻辑,我们将它重定向至被发现的引擎上。服务发现模块目前也支持外置的 Zookeeper,Server 就可以负载均衡的方式实现高可用。
前面讲到了对服务端Session请求的特殊处理让 Kyuubi 架构获得了多应用多引擎的能力。而 Kyuubi 多租户的设计则是为了在保证租户隔离的大前提下,合理的隔离和共享这些引擎。数据结构 Engine Space,是一个简单KV,其中 value 是引擎的随机地址,key 则包含多个部分,ServerSpace 用于隔离不同的 Kyuubi 集群,Version 用于版本隔离,防止兼容性问题,ShareLevel 是共享策略,应对不同工作负载,EngineType 用于隔离不同计算框架,EngineUser用于隔离租户,Subdomain 是用户自定义的隔离字段。KyuubiServer拿着客户端连接请求中的认证信息、配置信息生成对应的 Key,当我们能通过 key 获取到对应的引擎实例,就可以实现对该引擎实现共享,否则,就会进入引擎启动的逻辑,这个过程中,服务端会把 Key 传递给引擎端,引擎完成初始化后,会在 Engine Space 中插入自己的信息,这时服务端就可以拿到这个信息完成对应的连接了。
Kyuubi 通过服务注册发现实现负载均衡,来获得高可用能力和高客户端并发能力。作为一个常驻的服务,不可避免的会遇到各种计划内或者计划外的停服事件,比如服务端的各类硬件或者软件故障,升级操作等。通过服务注册发现机制,我们对计划内的维护升级操作,可以实现“平滑下线”。对计划外的单点故障,可以提供客户端重试的机制,保证任务的容错能力。同时,在高可用模式下,引擎依然遵循 Kyuubi 多租户的对应关系来实现隔离和共享。
综合引擎启动耗时、单引擎的负载能力,集群整体资源利用率等因素,并为了满足不同大数据工作负载对资源隔离共享,稳定性性能、响应时间的不同诉求,我们引入了不同粒度的引擎隔离共享策略。分别是基于连接、用户、用户组和Server 四个粒度。举例来说,基于连接的共享模式,连接和引擎是一对一的关系,每个连接都有一个自己的独立引擎,其他任何人或连接都无法访问。这种模式可以提供良好的隔离性使得它也可以胜任一些大型的批处理作业。在这种模式下,连接关闭时,引擎会及时关闭,释放所有计算资源。再比如,基于用户的共享模式,默认情况下,用户和引擎是一对一的关系,每个用户都有一个自己的独立引擎,其他任何人都无法访问,而来自同一用户的连接则可以复用这个引擎。对于一个分析师来讲,他所有的连接只有一次包含比较耗时的引擎启动,其他的都可以快速响应,可以比较愉快的进行交互式分析。
对于一个多租户集群而言,为了较好的提升集群整体的资源利用率,除了可以充分利用YARN 和 K8s 等资源调度管理服务的能力之外,对于单个引擎而言,我们也实现了二级的资源弹性能力。在引擎之上,我们合理设置引擎的空闲 TTL 时间,来实现它的资源复用和回收。在引擎之内,我们可以开启 Spark 提供的动态资源分配功能,合理设置最大可分配 Executor 个数及Executor 空闲 TTL,来实现 Executor 的资源复用和回收。
从服务化的角度,弹性资源的能力让我们可以根据作业实际的负载去申请和使用资源,而 Spark 3.0 之后引入的自适应查询引擎则可以让这个过程更加的“智能”。它可以利用中间计算结果的统计信息,进一步优化后续的执行计划,实现动态合并 Shuffle 分区、动态选择 Join 策略、动态的处理 Join 中的数据倾斜问题等。我们内部在实践和落地这个特性的时候,也发现了不少的问题,很多优化根据“上游优先”的开源玩法,我们都推到了 Spark 社区中。而一些更加符合 Kyuubi 场景的特性或者暂时合不进去的,都以可扩展插件的方式在 Kyuubi 社区中维护。比如对于合并分区规则,一个静态的推荐合并大小参数,一方面很难在各种复杂算子间取得平衡,另一方面对于写场景,通常我们期望一个较大的参数值来规避小文件的产生,在这种情况下,中间过程的并行度也会收到影响,影响整个作业的性能。对于这个问题,Kyuubi 引入了 Stage 级别的配置隔离策略,单独对最后 Stage 的参数进行配置,同时保证中间并发和最终文件的输出大小。其他,我们还引入增加数据倾斜命中的规则、Z-Order 索引等拓展。此外,Kyuubi 也支持用户在 Spark 所提供的可扩展点上的任意自定义扩展。
Kyuubi使用场景
在第三部分,我们简单介绍下 Kyuubi 的使用场景
我们在社区的Github讨论区有一个编号为925的的单独讨论帖,来收集用户的使用场景。总的来说,大部分的用户都采用 Kyuubi 来替换 HiveServer2 来提升性能,弥补 Spark Thrift Server在场景和拓展能力上的不足。其次,是基于 Kyuubi 加 Spark on K8s 的能力提供大数据上云的能力,实现离线在线业务混部,降低IT设施的总拥有成本。最后,是整合 Hudi、Iceberg 等数据湖框架,搭建数据湖分析平台。从目前的讨论帖登记情况来看,Kyuubi在不同行业的很多公司都有成功的落地实践,比如视频领域的 B 站和爱奇艺,提供云上大数据服务的腾讯云和中国移动移动云,T3 出行的 Apache Hudi PMC 杨华老师团队也整合 Kyuubi 和 Hudi 打造了 T3 的数据湖平台。这些社区用户中,也涌现了不少社区贡献者,同时,我们在这些案例分享中,也吸收了不少灵感。欢迎大家来使用 Kyuubi 项目并与社区分享你们的实践案例。
Kyuubi开放社区
最后,我们来简单回顾下 Kyuubi 开放社区的建设和发展。
Kyuubi 最早在2018年从网易魔改的内部 Spark 分支中独立出来并开源,一直遵循 Apache Licence 2.0 版本开源协议。最初的目的是为了引入多租户能力,满足 Spark 权限控制的需求。2020年低,完成了新架构的设计和对 Spark 3.0 的支持,应用场景也更加丰富,这些变化带来了不少新用户和贡献者。Apache软件基金会是全球最大的开源组织之一,很多知名的大数据项目如 Hadoop / Spark / Hive 等都在其指导下孵化成为顶级项目,Kyuubi 和这些项目的生态关系,也为了社区的进一步,让我们社区有了进入 Apache 社区孵化的想法。2021年6月,这个想法成为现实,我们顺利进入 Apache 软件基金会孵。Kyuubi 进入 Apache 基金会的目的是希望在 Apache 基金会的帮助下,构建一个厂商中立的多元化社区,推动 Kyuubi 项目的发展。在2021年的上半年,在社区小伙伴的共同努力下,我们成功发布了1.3.0、1.3.1 和的1.4.0 一共3 个 Apache release 版本。
“Community Over Code”/ “社区大于代码”是 Apache 不变的宗旨,它是一种鼓励长期协作和保持项目稳定的方式。Apache Kyuubi 社区希望有兴趣的小伙伴可以加入我们,你可以分享你的实践案例,订阅邮件列表关注社区动态,提个问题报个BUG,当然也可以直接来帮助我们修复文档,测试和代码。对英文文档有一定障碍的同学,可以关注我们的公众号,我们也在努力生产中文指南。
Kyuubi在移动云的实践
项目背景
私有云项目需要一个支持多用户Spark的能力,移动云Lakehouse需要提供jdbc能力,因Hive on Spark对Spark版本有较强的依赖,所以调研了Spark Thrift Server on k8s和Apache Kyuubi。
- Spark Thrift Server,本质上就是一个 Spark 应用在多线程场景下的应用。它在运行时启动一个由 Driver 和 Executor 组成的分布式 SQL 引擎。在 SQL 解析层,该服务可充分利用 Spark SQL 优化器的能力,在计算执行层,由于 Spark Thrift Server是常驻类型的应用,没有启动开销,当没有开启动态分配的情况下,整个 SQL 的计算过程为纯的线程调度模式,性能极佳。其本质上是一个 Spark Application。用一个 Spark Application 去响应成千上万的客户端请求,一般会存在较大限制。
- Apache Kyuubi,Kyuubi是对Spark Thrift Server的加强版,Kyuubi 在统一接口基础上,拓展了 Spark Thrift Server 在多租户模式下的使用场景,并依托多租户概念获得了完善的资源隔离共享能力和数据安全隔离的能力。而得益于 Kyuubi Server 和 Engine 松耦合的架构极大提升了服务自身的并发能力和服务稳定性。
对比 Apache Kyuubi 和 Spark Thrift Server我们发现,Kyuubi 在租户控制,任务资源隔离,引擎升级对接,性能等方面拥有诸多优势。
架构位置
Lakehouse中和Kyuubi相关的服务大致可以分为4类。
- 服务提供:Lakehouse面向用户层面的服务接口,Kyuubi提供JDBC能力。
- 管理服务:Job manager主要处理由console和Open api提交的离线批处理任务,resouce manager负责用户实例的资源分配,log manager服务日志采集并提供SQL审计接口。
- 计算引擎:为用户提供OLAP、即席查询以及数据迁移。
- 数据存储:底层存储主要为HDFS和移动云EOS对象存储,格式上支持Hive表和Hudi表。
移动云端实践
① Kyuubi on ecloud
社区版Kyuubi是由用户决定自己需要多少资源,Kyuubi在k8s或yarn上启动spark。
由于在移动场景中每个实例的资源是有限制的,我们基于移动云使用场景做了改进:
- 资源管理:资源统一由Lakehouse资源调度管理,和console共用实例资源;所有的资源由resource schedule分配和控制;禁止用户指定引擎相关参数。
- 用户认证:在自定义认证的基础上,实现基于移动云AccessKey、SecretKey方式认证授权。
- 日志审计:对接lakehouse SQL审计平台。
- SQL分析与拦截:通过Kyuubi扩展插件实现了SQL前置分析、语法限制以及对象存储信息的动态加载。
② Kyuubi on kubernetes部署方式
- 使用Helm3管理Kyuubi相关服务
- 使用Depolyment方式部署Kyuubi server
- 使用LoadBalancer service提供server高可用和负载均衡
- 与ZooKeeper解耦,使用etcd提供ServiceDiscovery
③ Kyuubi with trino
Kyuubi通过gateway的方式实现对trino集群的访问。Trino engine会以Client的形式通过http请求与集群通信,获取计算结果。与Spark engine类似,获取到结果数据后,会将其转换为hiveserver2对应的数据类型。最后,通过thrift协议将结果返回给Kyuubi srever并提供给用户。其结构如上图所示。
Kyuubi with trino的优点如下:
- 引擎和服务解耦,在kyuubi中统一实现用户认证、SQL预处理,审计等工作,引擎只需要关注内核优化,便于升级;
- 统一JDBC服务,只需要有一个JDBCserver,用户只需在连接时指定engine类型,通过参数指定所需要的引擎:spark、trino、flink。
今天的分享就到这里,谢谢大家。
分享嘉宾
本文转载自姚琴 洪冬冬,原文链接:https://mp.weixin.qq.com/s/JfB7Y3J666-aEuHx9aA4JA。