【Spark与Kyuubi(2)】从一条 JDBC 查询开始,看懂 STS 为什么撑不住,以及 Kyuubi 为什么能解

很多人对 Spark Thrift Server(STS)的印象是:

“能跑,但一多用户就出问题。”

但很少有人从一条 SQL 的完整生命周期,把问题说清楚。

这篇文章只做两件事:

  1. JDBC → Driver → Executor → YARN 的完整调用链,按时间顺序拆开
  2. 用同一条链路,解释 Kyuubi 是怎么把 STS 的 7 个结构性问题逐个拆掉的

一、一条 SQL 在 STS 里,到底走了什么路

假设你从 BI 工具点了一下刷新:

SELECT dept, sum(amount) FROM t_order GROUP BY dept;

1️⃣ JDBC 层:入口很简单,但“太集中”

BI 工具通过 JDBC 连接:

jdbc:hive2://sts-host:10000

背后发生的是:

  • 一个 Thrift 连接被 STS 的 HiveServer2 接收
  • STS 内部维护一个 JDBC Session(用户身份、临时视图)
  • 所有 Session 都落在同一个 JVM 里

👉 到这里,第一个隐患已经埋下: 连接可以很多,但大脑只有一个。


2️⃣ Driver:大脑开始干活

这条 SQL 进入 Driver,顺序非常固定:

SQL 字符串
 ↓
Parser(ANTLR)→ Unresolved Logical Plan
 ↓
Analyzer(查 Catalog,绑定表/列)
 ↓
Catalyst Optimizer(RBO / CBO)
 ↓
SparkPlanner → Physical Plan(DAG)

然后进入调度层:

DAGScheduler
  └── 按 Shuffle 切 Stage
TaskScheduler
  └── 把 Task 封装成对象,等待 Executor

注意一个关键事实:

这些步骤,100% 发生在一个 Driver JVM 里,而且是所有用户共享这一个 JVM。


3️⃣ Executor:劳工,但不认识“用户”

Driver 向 YARN 申请到 Container 后,Executor 启动。

Executor 内部:

  • 接收 Task
  • 读 Parquet / HDFS
  • 做 Aggregate
  • Shuffle Write / Shuffle Read

Executor 只知道一件事:

“Driver 让我算这个 Task。”

它不知道:

  • 这是谁发的 SQL
  • 属于哪个部门
  • 该不该限制资源

4️⃣ YARN:只认识 Application,不认识 SQL

在 YARN 眼里,整个 STS 是:

一个 Application
├── 一个用户(spark / hive)
├── 一个 Queue
├── 一组 Container(Driver + Executors)

无论你背后有 1 个用户还是 100 个用户,YARN 看到的信息完全不变。


5️⃣ 结果回流:Driver 再当一次中转站

SQL 执行完:

  • 小结果:collect() 回 Driver
  • Driver 通过 Thrift 一行行发给 JDBC 客户端
  • 大结果:写 HDFS,再让客户端读

Driver 同时是:

  • 调度器
  • 编译器
  • 结果缓冲区

把这条链画成一句话

JDBC 连接很多
   ↓
同一个 Driver 编译 + 调度
   ↓
同一组 Executor 计算
   ↓
YARN 只看到一个 App

所有问题,都长在这条链上。

 

二、STS 的 7 个问题,本质都是“链上断点”

断点位置问题表现
所有 Session → 一个 Driver共享 Driver,用户互相影响
Driver 串行调度高并发压垮 Driver
Executor 共享一个烂 SQL 拖死所有人
YARN 只看 App队列、用户无法精细控制
Driver 单 JVM一挂全挂
Executor 生命周期 = AppSQL 结束资源不释放
无用户维度无法按租户治理

STS 不是“没调好”,而是: 这条链路从设计上,就不是一个多租户服务。


三、Kyuubi 进来后,链路被改成了什么

Kyuubi 的核心思想,可以用一句话概括:

不在一个 Driver 里服务所有用户,而是让每个用户(或租户)拥有自己的 Driver。

它把原来的“单点大脑”,拆成两层。


四、Kyuubi 的新链路:先看架构分层

JDBC Client
   ↓
Kyuubi Server(无状态网关)
   ↓  ──────── 按用户 / 租户路由 ───────
         ┌───────────────┐
         │ Spark Engine  │  ← 一个 Spark App
         │  (Driver A)   │
         └───────────────┘
         ┌───────────────┐
         │ Spark Engine  │
         │  (Driver B)   │
         └───────────────┘
  • Kyuubi Server:只干接入、认证、路由
  • Spark Engine:就是一个 Spark Application(等价于一个 STS,但只服务一部分人

五、同一条 SQL,在 Kyuubi 里怎么走

还是那条 SQL。

1️⃣ JDBC → Kyuubi Server

BI 连接的是 Kyuubi:

jdbc:hive2://kyuubi-host:10009

Kyuubi Server 收到后:

  • 解析用户名 / 组(LDAP / Kerberos / Ranger)
  • 决定这个用户属于哪个 Engine Pool
  • 找已有 Engine,或拉起一个新的

👉 这一步,STS 没有。


2️⃣ Engine = 专属 Driver

如果这是用户第一次连接:

  • Kyuubi 用 spark-submit 启动一个 Spark Application
  • 这个 App 里运行 KyuubiSparkEngine
  • Engine 内部:
    • 有自己的 Driver
    • 有自己的 Executor
    • 向 YARN 注册成一个 独立 Application

现在链路变成:

用户 A 的 SQL → Engine A(Driver A)
用户 B 的 SQL → Engine B(Driver B)

3️⃣ Driver 内:和 STS 一模一样,但范围变小了

Engine 内部的 Driver,做的事和 STS 一样:

  • 解析 SQL
  • 优化
  • 切 Stage
  • 调度 Task

区别是:

这个 Driver 只服务一个用户 / 一个组。


4️⃣ Executor:终于可以“认人”了 (资源隔离,不同用户会调度到不同的运行资源)

因为 Engine 是独立的 Spark App:

  • 每个 Engine 有自己专属的 Executor
  • 这些 Executor 只跑这个 Engine 的 Task

YARN 看到的是:

App1 → 用户 A → Queue A
App2 → 用户 B → Queue B

👉 队列、资源、权限,第一次对齐到“人”。


5️⃣ 结果回流:网关只做转发

Engine 把结果返回给 Kyuubi Server:

  • Kyuubi Server 不计算
  • 不编译 SQL
  • 不维护物理计划
  • 只负责 Thrift RPC 转发

Driver 不再是“接入 + 调度 + 结果中转”三合一。


六、逐条对照:Kyuubi 怎么解决 STS 的问题

1️⃣ STS:所有用户共享 Driver

Kyuubi:一人一个 Engine

  • 用户 A 的烂 SQL 只打爆自己的 Driver
  • 用户 B 完全无感

2️⃣ STS:Driver 高并发瓶颈

Kyuubi:压力被 Engine 水平拆分

  • 原来:100 个连接 → 1 个 Driver
  • 现在:100 个连接 → 10 个 Engine,每个 10 个连接

Driver 不再是全局瓶颈。


3️⃣ STS:用户资源不隔离

Kyuubi:Executor 天然隔离

  • 一个 Engine OOM → 只杀这个 Engine
  • 其他 Engine 的 Executor 不受影响

4️⃣ STS:一挂全挂

Kyuubi:Engine 是独立 Application

  • 某个 Engine Driver 挂了
  • Kyuubi Server 还在
  • 其他用户继续用
  • 这个用户下次连,自动拉新 Engine

5️⃣ STS:YARN 队列控制不精细

Kyuubi:每个 Engine 是独立 App

可以配置:

user A → queue.finance
user B → queue.bi

Kyuubi 在 spark-submit Engine 时,直接带:

--queue queue.finance

YARN 第一次“看见用户”。


6️⃣ STS:生命周期耦合

Kyuubi:Engine 可自动销毁

Kyuubi 支持:

  • 空闲 Engine 自动退出
  • SQL 结束 → Executor 回收(Dynamic Allocation)

App 生命周期 ≈ 用户活跃周期,而不是“永远活着”。


7️⃣ STS:无法按租户治理

Kyuubi:天然多租户模型

  • 可以统计:每个 Engine 的 CPU / 内存
  • 可以限制:单用户最大 Engine 数
  • 可以限制:单个 Engine 的 core / memory

治理从“猜”变成“可观测”。


七、一句话对比两条链路

STS 的链路

JDBC
 ↓
一个 Driver(所有用户)
 ↓
一组 Executor(所有人)
 ↓
YARN:一个 App

Kyuubi 的链路

JDBC
 ↓
无状态网关
 ↓
按用户路由
 ↓
专属 Driver
 ↓
专属 Executor
 ↓
YARN:多个 App

八、本质差异不是“功能”,而是“抽象”

STS 的假设是:

Spark 是一个计算引擎,我给它加个 JDBC 壳。

Kyuubi 的假设是:

数据服务应该是多租户系统,Spark 只是计算内核。

所以:

  • STS 把 Spark 当成“服务进程”
  • Kyuubi 把 Spark 当成“可被编排的计算单元”

九、最后给架构师的一句话

如果你今天还在用 STS,而且:

  • 用户数 > 10
  • 有部门隔离诉求
  • 有 SLA 要求

那么问题从来不是:

“STS 参数怎么调?”

而是:

“你是否需要一个真正的多租户 SQL Gateway。”

Kyuubi 的答案,不在功能列表里,而在那条被拆开的 Driver 链路上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值