Flink SQL 基础:架构、环境与 API 关系
好,咱们正式开始接触 Flink SQL。这一章我打算从三个角度切入:Flink 到底长什么样、怎么把环境搭起来、以及 Table API 和 SQL 到底谁是谁的“马甲”。
说白了,Flink SQL 不是凭空冒出来的东西。它背后是一整套流处理引擎在撑着。你如果只把它当 SQL 用,那有点浪费。我习惯先看架构,再动手搭环境,最后搞清楚 API 的定位——这样后面写查询的时候,心里才有底。
Flink 架构简介:它到底怎么跑的?
先看一张图,把 Flink 的核心角色理清楚。
这张图我画得比较简洁,但核心角色都在了。
- Client:你写好的 SQL 或者代码,通过 Client 提交给集群。它负责把作业打包、解析、扔给 JobManager。
- JobManager:整个作业的“大脑”。它决定谁先跑、谁后跑、失败了怎么恢复。检查点(checkpoint)也是它管的。
- TaskManager:真正干活的“工人”。每个 TaskManager 里有多个 Slot,Slot 就是并行度的最小单位。
我记得刚接触 Flink 时,总搞不清 Slot 和并行度的关系。后来踩了个坑:我把 Slot 数设成 1,并行度设成 4,结果作业一直排队。你想想看,Slot 是物理资源槽,并行度是逻辑并发数——物理不够,逻辑再高也白搭。
Flink SQL 环境搭建:别被版本坑了
环境搭建这件事,说简单也简单,说烦也烦。我见过太多人卡在版本兼容性上。这里我直接给出一套我验证过的方案。
1. 下载与解压
# 我推荐 Flink 1.17 或 1.18,SQL 功能最稳定
wget https://dlcdn.apache.org/flink/flink-1.18.0/flink-1.18.0-bin-scala_2.12.tgz
tar -xzf flink-1.18.0-bin-scala_2.12.tgz
cd flink-1.18.0
2. 启动本地集群
# 启动单机版,默认 JobManager + 1 个 TaskManager
./bin/start-cluster.sh
# 检查是否启动成功
jps
# 应该看到:StandaloneSessionClusterEntrypoint(JobManager)
# TaskManagerRunner(TaskManager)
启动后,打开浏览器访问 http://localhost:8081,能看到 Flink Web UI。嗯,这一步如果看不到,八成是端口被占了,或者 Java 版本不对。Flink 1.18 要求 Java 11+。
3. 启动 SQL Client
# 进入 SQL 交互式客户端
./bin/sql-client.sh
看到 Flink SQL> 提示符,就说明环境搭好了。你可以试试:
Flink SQL> SELECT 'Hello Flink SQL' AS msg;
lib/ 目录下。
4. 常用配置速查
| 配置项 | 默认值 | 说明 |
|---|---|---|
taskmanager.numberOfTaskSlots |
1 | 每个 TaskManager 的 Slot 数 |
parallelism.default |
1 | 作业默认并行度 |
state.backend |
HashMap | 状态后端,生产用 RocksDB |
execution.runtime-mode |
STREAMING | 流模式 / 批模式 |
我个人习惯在 conf/flink-conf.yaml 里先把 parallelism.default 改成 2,这样本地测试时能看到并行效果,又不至于把笔记本跑崩。
Table API 与 SQL 的关系:一枚硬币的两面
很多人问我:“Table API 和 SQL 到底选哪个?”
我的回答是:它们本质上是同一套逻辑表达层的两种写法。SQL 是声明式的字符串,Table API 是程序式的链式调用。底层都翻译成相同的 Table 对象,再转成 DataStream 执行。
看个对比就清楚了:
// SQL 写法
Table result = tableEnv.sqlQuery(
"SELECT user, COUNT(*) AS cnt " +
"FROM clicks " +
"GROUP BY user"
);
// Table API 写法
Table result = tableEnv.from("clicks")
.groupBy($("user"))
.select($("user"), $("count").count().as("cnt"));
这两段代码,最终生成的执行计划一模一样。区别在哪?
- SQL:适合快速验证、临时查询、给数据分析师用。字符串形式,动态拼接方便。
- Table API:适合复杂逻辑、需要 IDE 自动补全、类型安全的场景。编译期就能发现字段名写错。
为什么会这样?因为 Flink 在 1.9 版本之后,把 Table API 和 SQL 的底层统一成了 Blink Planner。之前两个 Planner 并存,搞得大家很混乱。现在好了,一套优化器,两种入口。
我画了一张关系图,帮你理清层次:
你看,不管是 SQL 还是 Table API,最终都汇到 Table 对象,然后交给 Planner 去优化。Planner 会做谓词下推、投影裁剪、甚至把流转成批来优化性能。
tableEnv.sqlQuery() 把 SQL 结果转成 Table,再用 Table API 做后续处理——两边都舒服。