ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Kyuubi实战入门:打造统一SQL网关,盘活Spark多租户与高可用

Kyuubi实战入门:打造统一SQL网关,盘活Spark多租户与高可用 做数据平台项目久了你会发现一个特别真实的问题数仓和湖上从来不缺SQL能力缺的是一个好的“入口”。我接手过一个挺典型的场面——业务方要数据得排队等开发跑脚本分析师自己用DataGrip连集群却频繁超时运维这边看到用户每提交一次查询就launch一个Spark Application十几个executor的资源被稀稀拉拉地占着集群看起来不忙但内存早就见底了。这种时候SQL网关这个概念就不再是“锦上添花”而是必须落地的工程问题。我在评估过Spark自带的ThriftServer、也看过一些轻量自研方案之后把重心放到了Apache Kyuubi上部署过几个环境跑了接近两年中间踩过坑也排掉过不少疑难问题。这篇算是Kyuubi系列的第一篇先把地基打牢Kyuubi到底是什么它解决哪一类问题整体架构怎么设计以及怎么快速搭一个能用的SQL网关。后续系列里我打算再深入聊高可用细节、引擎调优、权限对接和监控体系这篇先把基础概念理清楚。1. 为什么要给大数据平台加一道SQL网关1.1 没有网关的时候SQL查询到底有多乱先还原一下没有SQL网关的场景。一个中型数据团队规模大概十几到几十人日常查数方式基本是各显神通开发人员写Spark SQL脚本用spark-submit跑批分析师在本地用各种BI工具直连HiveServer2还有一部分人习惯开个Spark Shell或Notebook。表面上看大家都能查数实际上隐患一堆。第一是资源管理失控。每个用户、每次查询都独立提交ApplicationSpark的executor是“谁申请谁占用”集群调度器看到的是一堆零散的小任务。你很难回答一个简单的问题这周到底谁在用资源、用了多少、有没有人能一次性占掉半个队列。我见过最夸张的一次一个分析师跑了个笛卡尔积直接拖垮了整个离线队列的调度。第二是连接管理混乱。各种工具直接连集群的HiveServer2或者Spark ThriftServer连接数一多服务端线程和内存一起爆。而且底层引擎一旦重启所有客户端全部掉线重连业务那边就是一堆“查数失败”的投诉。第三是权限和审计几乎没有。没有统一入口就很难在入口处做认证、鉴权和操作审计。数据出问题要追责的时候翻遍日志也说不清哪个用户在哪台机器上跑了什么SQL。这三个问题叠加起来你会发现瓶颈根本不在SQL执行引擎本身而在“接入层”。1.2 网关的定位把接入、管控与查询引擎解耦SQL网关的本质是在客户端和查询引擎之间加一层代理层。它不负责真正的计算计算还是在Spark、Flink这些引擎上完成但它管住了客户端怎么连、连到哪个引擎、引擎怎么被创建和回收、以及连进来的时候有没有资格、干了什么。用生活里的场景类比一下这就像一栋楼的门禁系统。楼里的房间Spark引擎不需要每个人都拿着钥匙所有人通过门禁网关刷卡进入门禁知道你是谁、能去哪一层、什么时候进的、什么时候出的。房间怎么分配、谁和谁共用都由物业网关统一安排而不是每个人自己撬门进去住。有了这一层最大的收益就是可控性。客户端不再需要知道底层Spark集群的地址、YARN队列、Kerberos票据这些细节只需要知道一个统一的JDBC地址。底层引擎升级、扩容、迁移对终端用户完全透明。1.3 为什么是Kyuubi而不是自己写或者用Spark ThriftServer很多人第一个疑问是Spark不是自带ThriftServer吗为什么还要额外搞一个Kyuubi这个坑我帮大家先踩过了。Spark自带的HiveThriftServer2在早期版本里最大的问题是单例模式——所有用户共享一个SparkContext一个用户的笨查询会直接影响全体用户的性能配置修改要重启高可用配置也非常麻烦做多实例的时候状态同步是个大坑。它适合小范围试用不适合作为正经的团队级网关。至于自研我劝大家除非团队有很强的平台研发能力否则别轻易走这条路。网关的核心难点不只是转发SQL而是引擎生命周期管理、故障恢复、权限透传、审计埋点、以及和YARN/K8s调度器的协同。这些坑每一步都需要时间试错Kyuubi作为Apache顶级项目恰好把这些能力都沉淀成了开箱即用的功能。它是网易开源出来的2021年进入Apache孵化器后顺利毕业社区活跃度很高版本迭代也快这也是我敢在生产环境长期用的原因。2. Kyuubi核心架构拆解前端与后端分离的设计思路2.1 架构角色划分理解Kyuubi最核心的是记住“前店后厂”的模型。“前店”是Kyuubi Server本身负责和所有客户端打交道“后厂”是一批按需创建的Spark或Flink引擎真正跑SQL干活。前台和后台通过内部RPC通信对客户端完全透明。从部署上看Kyuubi Server通常独立部署在一组专门的节点上和计算集群分离。多个Kyuubi Server实例可以组成一个集群通过ZooKeeper做服务发现和高可用。客户端使用的连接串里如果是ZK地址就能自动找一个可用的Server实例连上去任何一个Server挂掉客户端只需要重连就能切换到别的实例。2.2 前端处理Kyuubi Server的职责边界Kyuubi Server负责的是接入层的事情。它实现了HiveServer2协议所以任何支持Hive JDBC的客户端都能直接连beeline、DBeaver、DataGrip、各种BI工具甚至你自己写的JDBC代码基本零改造接入。Server端处理的事情包括连接认证、会话管理、操作提交、结果集转发以及与后端引擎之间的路由和状态同步。这里有个容易被忽略的设计Kyuubi Server本身是“有状态”的它会记录每个会话挂在哪台引擎上、当前引擎处于什么状态。但它的状态存储和恢复做得很轻巧借助ZK和引擎上报机制能做到某个Server宕机后新Server能够接管存量会话所在的引擎。对客户端而言一次重连就恢复工作这在生产环境的价值非常大。2.3 后端引擎管理创建、复用与回收Kyuubi最有技术含量的部分是它控制Spark引擎的整套生命周期。首次有用户发起连接时Server会向资源调度器YARN或K8s提交一个Spark Application这个Application起来之后会自动把自己注册回对应的Kyuubi Server。这个过程有点“按需点菜”的味道——引擎不是常驻的而是首个会话触发创建的之后同一租户或同一用户的后续会话会复用这个引擎。默认情况下同一个用户或同一个引擎共享组的多个会话会共享同一个SparkContext这就回到了Spark ThriftServer的单例问题不区别在于Kyuubi是按用户维度共享而不是全局共享。用户A的笨查询不会影响用户B的引擎因为它们的上下文完全隔离。这就是Kyuubi多租户能力的核心。引擎空闲之后也不会永远占着资源Kyuubi有超时回收机制。你可以设置engine idle timeout比如30分钟没有查询引擎就会自动释放归还Executor给集群。这解决了我前面提到的“资源被零散占着不吐”的问题——引擎是活期存款不是定期不用了就还回去。2.4 引擎的隔离级别与共享策略Kyuubi支持配置引擎的共享级别share level这是日常调优里非常关键的一个参数。默认是USER意思是同一个用户共享同一台引擎可以改成GROUP让一个租户或项目组共享也可以改成CONNECTION每个连接独占一台引擎。选择哪种级别取决于你的业务场景查数频繁、查询相对轻量的分析师团队用USER级共享能把资源利用率做得很高需要严格隔离的付费租户场景可能就得考虑CONNECTION级或者配合队列隔离。这个参数表面上只是个开关实际上是资源效率和隔离性之间的天平。我见过有人直接把所有用户都升级成CONNECTION隔离结果集群上引擎数量暴涨光元数据服务就被打挂了。反过来小团队强上USER共享一个复杂查询把全组拖慢的情况也遇到过。合理选择的前提是你要清楚自己的业务负载画像。3. 关键功能逐个聊多租户、高可用、权限与监控3.1 多租户隔离与资源配额多租户如果只理解成“每个用户一个引擎”那就太浅了。Kyuubi的多租户能力是分层设计的。第一层是引擎隔离前面已经提到不同用户在不同JVM里跑着各自的SparkContext互相之间连GC都不会影响。第二层是队列隔离Kyuubi允许引擎在提交时绑定到指定的YARN队列也可以动态配置比如把高管团队和普通分析师的查询放到不同队列让调度器层面的优先级生效。实际项目里我常把这两层配合起来用。对关键业务线给一个独立队列和一个专属引擎池保证它的查询延迟稳定对临时探索性查数放进共享队列和共享引擎池让它“能用但不娇气”。这样做还有一个隐藏好处某个租户如果出现恶性SQL爆炸半径被限制在自己的引擎和队列里不会波及其他租户。3.2 高可用与负载均衡的落地姿势Kyuubi的HA依赖ZooKeeper原理并不复杂每个Kyuubi Server启动后在ZK上注册一个临时节点多个Server之间通过ZooKeeper做leader选举客户端连接串里配置ZK地址客户端SDK从ZK拿到可用Server列表再选一个建立连接实现负载均衡。生产环境我一般部署三台Kyuubi Server每台的client流量都不大但是一定要保证冗余度。需要注意的是ZK本身的稳定性Kyuubi Server非常依赖ZK做服务发现和leader切换如果ZK抖动客户端会感觉连接间歇性不可用。所以我建议给Kyuubi单独规划一个ZK namespace和数据平台其他业务共用ZK集群的时候要格外留意ZK的写入负载。3.3 认证、授权与审计闭环Kyuubi支持多种认证方式生产环境常用的包括LDAP认证和Kerberos认证也支持自定义认证插件。连进来之后真正的权限控制有两层Kyuubi层可以做基础的库表级别授权底层Spark层还可以叠加Ranger之类的鉴权服务再加上行级、列级数据脱敏基本能满足大多数企业的数据安全要求。审计这块常被忽略但其实是上了网关之后白捡的福利。所有SQL操作都会经过Kyuubi ServerServer的日志天然就是一份查询审计记录。你可以开启操作日志持久化记录哪个用户在哪个时间点连上来、执行了什么SQL、落到哪个引擎上。真出了问题回溯链路比从前容易一个数量级。3.4 监控指标与REST APIKyuubi对外暴露了一套REST API可以查Server的基本信息、会话列表、引擎列表和执行中的SQL。生产环境我建议直接把它的metrics接口接到Prometheus关键看几个指标引擎数量、活跃会话数、查询耗时分布、Server本身的JVM内存和GC。引擎数量是最直观的健康度指标——引擎数量异常上涨往往意味着有会话没有被回收或者有人把多个工具的连接池直接怼到网关上没断开。另外Kyuubi的Spark引擎也会把Spark UI和事件日志暴露出来你可以在Server上直接看到某个引擎内部跑了哪些Stage、有没有数据倾斜。排障的时候这个“从Session到Spark UI”的穿透能力帮我节省过很多时间。4. 从零部署Kyuubi的实操流程4.1 环境准备与版本选择先讲两个最容易出问题的点版本和依赖。Kyuubi本质上是“骑着”Spark工作的它和Spark版本有明确的匹配范围一定不要用太新的Kyuubi配一个很老的Spark也不要反向乱搭配。我在部署前会先查一下官方文档里的兼容性矩阵再决定组合。生产环境我建议用Kyuubi对应的默认Spark版本省心。另外Kyuubi运行需要JDK 8或11Hadoop客户端环境变量必须配好。部署模式上如果你只是快速验证可以直接在一台机器上以Local模式跑Kyuubi会启动本地的Spark引擎开箱即用。但生产环境肯定要对接YARN这需要你提前准备好Spark的YARN配置文件、HDFS的core-site.xml和hdfs-site.xml把它们放到Kyuubi能读到的地方。4.2 核心配置逐项讲解Kyuubi的主配置文件是kyuubi-defaults.conf我挑几个必须关心的配置项来展开。首先是端口和绑定地址kyuubi.frontend.bind.host0.0.0.0 kyuubi.frontend.bind.port10009然后是后端引擎的类型默认是Sparkkyuubi.engine.typeSPARK高可用相关启用ZKkyuubi.ha.enabledtrue kyuubi.ha.zookeeper.quorumzk01:2181,zk02:2181,zk03:2181 kyuubi.ha.zookeeper.namespacekyuubi引擎的资源控制也在这里配置kyuubi.engine.spark.memory4g kyuubi.engine.spark.yarn.queuedefault最后是引擎的回收和共享策略kyuubi.session.engine.idle.timeoutPT30M kyuubi.session.engine.check.intervalPT30S kyuubi.engine.engine.share.levelUSER这里我想单独解释一下kyuubi.session.engine.check.interval。它决定了Kyuubi Server多久检查一次引擎的空闲状态。这个值设置太短检查频繁但资源回收及时设置太长空闲引擎会多占一段时间资源。一般在30秒到1分钟之间比较合理不需要为了精确而把它压到几秒否则在引擎数量较大的集群上会给Server端平白增加压力。环境相关的变量写在kyuubi-env.sh里export SPARK_HOME/opt/spark export HADOOP_CONF_DIR/opt/hadoop/etc/hadoop export JAVA_HOME/opt/jdk1.84.3 启动验证与客户端连接启动很简单前台跑用bin/kyuubi run后台跑用bin/kyuubi start。日志默认打在logs目录下启动完成后用ss -lnt|grep 10009确认端口起来了再用beeline测一条SQL!connect jdbc:hive2://localhost:10009/default连接时如果需要账号密码取决于你配置的认证方式默认可能是anonymous。如果配了HA客户端连接串要换成ZK方式jdbc:hive2://zk01:2181,zk02:2181,zk03:2181/default;serviceDiscoveryModezooKeeper;zooKeeperNamespacekyuubi第一次执行SQL的时候你会看到系统在后台创建Spark引擎如果是YARN模式Application列表里会出现一个以KyuubiSparkSQLEngine为名字的任务。这个首次查询会比较慢因为引擎要申请资源、启动executor可能耗时30秒甚至一分钟。这是正常现象不代表网关有问题第二次及以后就快多了因为引擎已经复用了。我第一次部署的时候不知道这一点对着日志找了半天以为卡死了白白浪费了半小时。客户端的兼容面很广我用过的包括beeline、DataGrip、DBeaver、以及直接用Hive JDBC代码写的小工具都连过。只要对方声称支持HiveServer2协议基本上拿来就能用。5. 常见问题与排查思路实录5.1 引擎起不来的几种情况引擎创建失败是我遇到最多的一类问题症状是第一次查询一直卡在等待状态最终客户端报错。常见的几个原因第一YARN队列资源不足引擎的Application提交后被调度器一直等待这种情况去YARN的ResourceManager页面看App状态就一目了然第二Spark和Hadoop配置有问题引擎启动后连不上HDFS这个要看Kyuubi Server日志里的引擎日志路径通常里面有具体的ClassNotFoundException或者连不上NameNode的报错第三Kerberos票据问题如果集群开了安全认证Kyuubi Server要有合法的keytab才能代用户提交引擎。排查这类问题我有个习惯先看Server端日志里有没有记录引擎日志的具体路径直接去拉Spark引擎自己的日志。把两层日志对上号问题基本就定位了。不要只看一层日志引擎在YARN那边Server这边能看到的只是代理反馈。5.2 连接超时与高并发下的连接池问题连接超时的一种隐蔽成因是客户端连接池使用不当。有些BI工具或者代码框架会对同一个JDBC地址建立大量连接但连接其实是有会话上限的超过之后新连接会排队等待。表现就是时好时坏一会儿能查一会儿连接报错。这种情况下我通常不会立刻怀疑Kyuubi本身而是先去看活跃会话数。如果会话数居高不下且持续累积那大概率是客户端那边的连接池把连接“借”了没有还导致Kyuubi侧堆积了大量空闲会话。解决办法是调整客户端连接池的最大大小和空闲回收策略同时在Kyuubi侧设置合适的会话空闲超时让不活跃的连接自动被清理。5.3 版本兼容与依赖冲突的坑版本问题重灾区在Spark和Hadoop的组合上。有的环境里Spark已经集成了一些自定义的Hive依赖Kyuubi引擎启动时可能会遇到类和jar包的冲突。这类问题报错信息通常是一堆NoSuchMethodError或者LinkageError看多了就知道是版本互踩。我的建议很朴素Kyuubi部署的节点上尽量只让Kyuubi管理它自己的Spark依赖别把业务侧的Spark包顺手塞进去。Kyuubi对引擎依赖的jar包有隔离机制但前提是你的环境变量没把它搞乱。有一次为了让某个自定义函数生效我往SPARK_HOME/jars里加了几个包结果直接把Kyuubi引擎搞到起不来回滚之后就好了。从那以后我坚持用“最小化改动”原则Kyuubi节点上的Spark只服务Kyuubi不兼任其他用途。5.4 引擎不回收导致资源泄漏引擎空闲超时设置了但有时引擎还是一直挂着不回收。我排查下来最常见的原因是“空闲”的定义和你想的不一样。Kyuubi的空闲超时是从最后一次查询完成开始算如果客户端保持连接但没有任何查询这不算引擎忙碌但引擎也不会立刻被回收因为会话本身可能还处于active状态。换句话说引擎的回收和会话的存活是两套逻辑。要避免这种问题可以把会话空闲超时和引擎空闲超时一起配置让不活跃的连接先被清理然后引擎才有机会进入回收流程。还有就是要监控引擎数量曲线如果出现只涨不跌的迹象优先考虑是不是有客户端在做长连接保活定期发送无意义的ping。6. 落地建议与个人体会6.1 先从共享引擎起步再逐步走向精细隔离如果你所在的团队刚接触Kyuubi我建议不要一上来就搞复杂的多租户隔离先把网关跑通默认USER级共享让团队先用起来。这阶段重点解决的是统一入口、认证和审计问题收益立竿见影。等跑了一两个月你手里有了真实的查询频率、资源消耗数据再根据业务重要性做队列和引擎池的计划反而更容易落地因为你有数据支撑而不是拍脑袋隔离。6.2 把监控当成部署的一部分而不是部署完之后的事我个人最开始部署Kyuubi时只关注“能不能跑通”Prometheus和告警是后补的。结果真出问题的时候两眼一抹黑只能翻日志。后来我把监控前置部署清单里强制包含指标采集和基础告警反而后续运维轻松很多。大家别嫌我啰嗦监控这种事晚做一天代价就多一分。6.3 系列后续的预告与一个实用小技巧这篇既然是系列开篇很多主题只能点到为止。后面我打算分别展开聊聊高可用切换的真实演练记录、Spark引擎内存与并发的调优参数、Ranger权限对接的具体配置以及如何把Kyuubi查询日志接进数仓做成本分析。如果你们在用的过程中遇到什么奇葩问题也欢迎在评论里交流很多时候大家的踩坑记录比官方文档更解决问题。最后分享一个小技巧也是我每次排查性能问题时最先做的一件事在Kyuubi里对某个引擎开启Spark事件日志收集这样即使引擎已经Gone掉了你依然可以通过Spark History Server翻看当时的执行计划、Shuffle情况和GC状态。很多“灵异”性能问题最后都能从历史事件日志里找到答案。这个习惯帮我解决过好几次“看起来正常但就是慢”的疑难杂症强烈推荐你也试试。
返回列表