继续往下学 StarRocks,我们仍然只解决一个具体问题。
上一篇讲 MPP 时,我们知道了一条分析 SQL 可以交给多个节点并行处理。但当时留下了一个问题:
SQL 是谁接收的?谁来安排任务?又是谁真正读取和计算数据?
答案就藏在 StarRocks 最常见的两个角色里:FE 和 BE。
如果你还没看过上一篇,可以先从这里开始:
👉《一条 SQL,为什么能让多台机器一起算?StarRocks 的 MPP 终于讲明白了》
这一篇不展开复杂的内部实现,也不增加一串新名词。我们只跟着一条 SQL 走一遍,把 FE 和 BE 的分工真正弄明白。
还是从一条业务查询开始
假设运营想查看本月各城市的销售额。
报表系统在背后向 StarRocks 提交了这样一条 SQL:
SELECT
city,
SUM(amount) AS sales
FROM orders
WHERE order_time >= '2026-07-01'
AND order_time < '2026-08-01'
GROUP BY city;
我们看到的是一条完整的 SQL,但 StarRocks 不能收到以后就直接“开算”。
它至少要先回答这些问题:
-
orders表是否存在; -
city、amount和order_time这些列是否存在; -
需要读取哪些数据;
-
应该先过滤,还是先聚合;
-
哪些 BE 上有这次查询需要的数据;
-
怎样安排多个 BE 一起处理。
这些工作并不都由同一个节点完成。
先用一句话分清 FE 和 BE
在本文讨论的存算一体架构中,可以先这样记:
FE 负责接收 SQL、生成执行计划并安排查询;BE 负责保存数据、读取数据并完成实际计算。
如果再压缩一点:
FE:接、想、派
BE:存、读、算
这里的“想”不是说 FE 像人一样思考,而是指它会理解 SQL,生成一份可以执行的计划。
图 1:FE 负责连接、规划和调度;BE 负责保存并处理数据。
这个分工很重要,因为它能避免两个常见的混淆:
-
FE 会参与查询,但它不是读取海量明细并完成主要计算的节点;
-
BE 会执行任务,但它不是各自随意决定整条 SQL 应该怎样执行。
下面分别来看。
FE 到底负责什么
FE 的全称是Frontend。
客户端连接 StarRocks、提交 SQL 时,首先接触到的是 FE。对一条查询来说,FE 的主要工作可以概括成四件事。
1. 接收客户端连接和 SQL
StarRocks 兼容 MySQL 协议,因此 MySQL Client、JDBC、报表工具或业务程序,都可以通过相应方式连接到 StarRocks。
用户提交的 SQL 会先到 FE。
2. 根据元数据检查 SQL
FE 管理着表结构等元数据。
可以把元数据理解成“描述数据的数据”,例如:
-
库和表叫什么;
-
表里有哪些列;
-
每一列是什么类型;
-
数据怎样组织和分布。
所以 FE 能判断 SQL 中的表和列是否存在,也能知道这次查询涉及哪些数据。
注意,FE 管理的是这些描述信息,不等于所有业务明细都保存在 FE 中。
3. 生成执行计划
SQL 只说明“我想得到什么结果”,并没有把每一步执行方法全部写出来。
还是以上面的查询为例,FE 需要规划:
读取 orders 中相关数据
↓
按照时间范围过滤
↓
读取 city 和 amount
↓
按照 city 聚合
↓
形成查询结果
实际执行计划会比这更复杂,但初学阶段只要知道:FE 会把 SQL 转换成 BE 能够执行的计划。
4. 把任务安排给 BE
执行计划生成后,FE 会结合数据分布等信息,把查询任务安排到相关的 BE 上。
这里不是把 SQL 原文简单复制给每个 BE,也不是让某个 BE 负责 WHERE、另一个 BE 只负责 GROUP BY。
更容易理解的情况是:多个 BE 按照同一份整体计划,各自处理自己负责的那部分数据,然后再把结果继续汇总。
所以,FE 更像查询的组织者:它知道要做什么、涉及哪些数据,以及任务应该怎样被安排。
BE 到底负责什么
BE 的全称是Backend。
在本文讨论的存算一体架构中,BE 同时承担数据存储和 SQL 执行。真正需要消耗大量 CPU、内存和磁盘读写的工作,主要发生在 BE 上。
1. 保存业务数据
订单明细、销售记录等真正用于分析的数据,会分布在各个 BE 上。
例如,为了便于理解,我们暂时把它想象成:
BE 1:保存一部分订单数据
BE 2:保存一部分订单数据
BE 3:保存一部分订单数据
这只是帮助理解的简化表达。数据到底怎样分布,和分区、分桶等设计有关,我们放到下一篇再讲。
2. 读取查询需要的数据
FE 安排查询后,相关 BE 会读取自己负责的数据。
如果查询只需要 7 月份的 city 和 amount,执行时就会尽量围绕这些条件和列进行读取,而不是把所有数据都交给 FE 再处理。
3. 完成过滤、聚合等计算
BE 会执行真正的数据计算,例如:
-
按时间过滤订单;
-
读取指定列;
-
计算
SUM(amount); -
按
city分组; -
处理排序、关联等其他计算。
多个 BE 可以同时处理不同部分的数据,这就是上一篇所讲的 MPP 在节点层面的体现。
一条 SQL 是怎样走完整个流程的
现在把 FE 和 BE 放在一起,再跟着这条 SQL 走一遍。
第一步:报表系统把 SQL 发给 FE
报表系统负责发起查询。它只需要提交一条完整 SQL,不需要知道集群内部有几个 BE,也不需要自己把 SQL 拆开。
第二步:FE 检查并规划查询
FE 根据元数据理解 SQL,确认涉及的表、列和数据范围,然后生成执行计划。
第三步:FE 把任务安排到相关 BE
FE 根据执行计划和数据分布,选择需要参与查询的 BE,并把相应任务安排下去。
第四步:多个 BE 并行处理数据
各个 BE 读取自己负责的那部分订单数据,并完成过滤和部分聚合。
例如:
BE 1:处理自己保存的 7 月订单,得到部分城市销售额
BE 2:处理自己保存的 7 月订单,得到部分城市销售额
BE 3:处理自己保存的 7 月订单,得到部分城市销售额
它们处理的是不同数据,但目标相同:为这一次查询计算结果。
第五步:汇总结果并返回客户端
各个 BE 产生的结果会继续交换和汇总,形成最终的城市销售额。完成后,查询结果再返回给报表系统。
图 2:客户端只提交一条 SQL;FE 负责规划和调度,多个 BE 负责并行读取与计算数据。
把细节先收起来,整条路径就是:
客户端提交 SQL
↓
FE 接收、检查、规划和调度
↓
多个 BE 读取并处理不同部分的数据
↓
结果汇总
↓
返回客户端
为什么要把 FE 和 BE 分开
看到这里,可能会产生一个问题:为什么不让每个节点什么都做?
因为“管理和安排查询”与“处理大量数据”是两类不同的工作。
FE 集中掌握元数据和查询计划,能够从整个查询的角度进行组织;BE 则把主要资源用于数据存储和计算。这样的分工让集群更容易把一条查询协调起来,也让多个 BE 可以共同承担数据处理压力。
当数据量和查询压力增加时,可以通过增加 BE 扩展存储和计算能力。不过这并不意味着增加一台 BE,所有查询都会按固定比例变快。实际效果仍然与数据分布、查询写法、执行计划和节点负载有关。
工作中看到这些现象时,可以怎样理解
理解 FE 和 BE 的分工后,一些常见现象就没那么神秘了。
SQL 连接不上,先看 FE 方向
因为客户端连接和 SQL 接收由 FE 负责,所以连接地址、端口、账号权限或 FE 状态,通常是排查入口。
这不代表所有连接问题一定由 FE 故障引起,只是排查时应该先确认这一层是否正常。
查询能提交,但执行很慢,要继续看 BE 和执行过程
SQL 能被接收,只能说明查询已经进入系统。真正读取和计算大量数据的是 BE,因此还要关注:
-
参与查询的 BE 是否正常;
-
数据是否分布不均;
-
是否读取了过多数据;
-
聚合、排序或关联是否消耗了大量资源。
FE 和 BE 都很重要,但职责不一样
没有 FE,客户端难以提交和组织查询;没有 BE,数据无处存放,也没有节点真正完成计算。
因此不能简单地说谁“更重要”。更准确的理解是:FE 让查询有计划地执行,BE 把计划变成真实的计算结果。
最后,只记住这三句话
如果读完整篇只打算带走三个结论,可以记住:
第一,客户端提交的仍然是一条完整 SQL,首先由 FE 接收。
第二,FE 负责元数据、查询规划和调度,不负责完成主要的数据计算。
第三,BE 保存并读取数据,多个 BE 可以按照计划并行完成计算。
再把它压缩成最容易复习的一行:
FE:接、想、派;BE:存、读、算。
到这里,我们已经知道一条 SQL 为什么能交给多个节点计算,也知道 FE 和 BE 在其中分别做什么。
但还有一个关键问题没有回答:
数据为什么会分布在不同 BE 上?分区和分桶分别解决什么问题?
下一篇,我们就从这个问题继续。