第 1 章 Flink 概述
【学习目标】
理解 Flink 的定义,能解释"框架与分布式处理引擎""无界/有界数据流""有状态计算"等关键词;
了解 Flink 从 Stratosphere 项目到 Flink 2.x 的发展脉络,以及阿里 Blink 分支的贡献;
知道官方网站、官方文档、安装包下载等学习资源的获取途径。
1.1 Flink 是什么
Apache Flink 是一个框架 和分布式处理引擎 ,用于对无界和有界数据流 进行有状态计算 。Flink 被设计为可在所有常见的集群环境中运行,以内存执行速度 和任意规模来执行计算。
这句官方定义是理解 Flink 的钥匙,其中包含四个关键词,需要逐一理解:
| 关键词 | 含义解读 |
|---|---|
| 框架 / 分布式处理引擎 | Flink 既不是数据库,也不是消息队列,而是运行在集群之上、负责调度并执行计算任务的引擎。开发者只需编写计算逻辑,分布式执行、容错恢复等工作由 Flink 负责。 |
| 无界数据流 | 数据源源不断产生、没有明确终点,例如网站的实时访问日志、传感器的持续上报。处理无界流必须"边来边算",不能等数据收集完再算。 |
| 有界数据流 | 数据有明确的起点和终点,例如昨天的订单文件。有界流本质上就是传统的批处理数据,Flink 把它视为"有限长度的流",用同一套引擎统一处理。 |
| 有状态计算 | 计算过程中需要"记住"之前处理过的信息。例如统计网站累计访问量,当前的计数值就是状态;Flink 负责状态的高效存储、一致性与故障恢复。 |
【课堂提问】 想一想:统计"双 11 当天实时成交额大屏"和"生成上个月的销售月报",分别对应无界流还是有界流?为什么?
1.2 Flink 的发展历程
1.2.1 从 Stratosphere 到 Apache 顶级项目
Flink 起源于 Stratosphere 项目。Stratosphere 是 2010~2014 年由 3 所地处柏林的大学和欧洲其他一些大学共同进行的研究项目。2014 年 4 月,Stratosphere 的代码被复制并捐赠给了 Apache 软件基金会,参加这个孵化项目的初始成员是 Stratosphere 系统的核心开发人员。同年 12 月,Flink 一跃成为 Apache 软件基金会的顶级项目。
Flink 虽然诞生得早(2010 年),但其实是"起大早、赶晚集",直到 2015 年才开始突然爆发热度,逐渐成为流式计算领域的主流引擎。
【知识拓展】为什么叫 Flink?
在德语中,Flink 一词表示"快速和灵巧"。项目采用一只松鼠的彩色图案作为 logo,这不仅是因为松鼠具有快速和灵巧的特点,还因为柏林的松鼠有一种迷人的红棕色,而 Flink 的松鼠 logo 拥有可爱的尾巴,尾巴的颜色与 Apache 软件基金会的 logo 颜色相呼应------也就是说,这是一只"Apache 风格"的松鼠。
1.2.2 阿里巴巴的 Blink 分支
在 Flink 被 Apache 提升为顶级项目之后,阿里巴巴实时计算团队决定在阿里内部建立一个 Flink 分支------Blink,并对 Flink 进行大量的修改和完善,让其适应阿里巴巴这种超大规模的业务场景。
-
Blink 于 2016 年上线,服务于阿里集团内部搜索、推荐、广告和蚂蚁等大量核心实时业务;
-
2019 年 1 月,Blink 正式开源,目前阿里 70% 的技术部门都在使用该版本;
-
Blink 相比 Flink 的优势主要体现在:对 SQL 语法更完善的支持 以及 SQL 执行性能的提升。Blink 的许多改进后来陆续合并回 Flink 主干,极大推动了 Flink SQL 的成熟。
1.2.3 迈入 Flink 2.0 时代
Apache Flink 社区已于 2024 年 10 月 23 日发布了 Flink 2.0 版本,这是自 Flink 1.0 发布以来的首个重大更新。Flink 2.0 引入了多项激动人心的功能和改进,包括:
-
存算分离的状态管理;
-
物化表(Materialized Table);
-
批作业自适应执行。
同时,Flink 2.0 也包含了一些不兼容的变更,其最初提供的预览版旨在让用户提前尝试新功能并收集反馈。此后社区持续迭代,于 2026 年 6 月发布了本讲义采用的 Flink 2.3.0 版本。
1.2.4 发展历程一览
| 时间 | 里程碑事件 |
|---|---|
| 2010 年 | Stratosphere 研究项目启动(柏林 3 所大学联合欧洲多所大学) |
| 2014 年 4 月 | 代码捐赠给 Apache 软件基金会,进入孵化器,更名为 Flink |
| 2014 年 12 月 | 成为 Apache 顶级项目 |
| 2015 年 | 热度开始爆发,进入工业界视野 |
| 2016 年 | 阿里巴巴内部分支 Blink 上线 |
| 2019 年 1 月 | Blink 正式开源 |
| 2024 年 10 月 | Flink 2.0 发布:Flink 1.0 以来的首个重大版本更新 |
| 2026 年 6 月 | Flink 2.3.0 发布(本讲义使用版本) |
1.3 官方学习资源
| 资源 | 地址 | 用途 |
|---|---|---|
| 官方网站 | Apache Flink® --- Stateful Computations over Data Streams | 了解项目动态、下载发行版 |
| 官方中文文档 | Apache Flink Documentation(中文) | 学习概念、API 与部署的权威资料 |
| 安装包下载 | 阿里云开源镜像站 --- flink-2.3.0 | 国内高速下载(详见第 4 章) |
【学习建议】 官方文档是最权威、更新最及时的资料。本讲义的架构与 API 章节即以官方文档为蓝本整理,建议同学们课后对照官方文档阅读,培养查阅一手资料的习惯。
本章小结
-
Flink 是一个用于对无界和有界数据流 进行有状态计算的分布式处理引擎,以内存执行速度和任意规模运行;
-
Flink 起源于柏林的 Stratosphere 研究项目,2014 年捐赠给 Apache,并在同年成为 Apache 顶级项目;
-
阿里巴巴的 Blink 分支在 SQL 支持与执行性能方面做出了重要贡献,于 2019 年开源;
-
Flink 2.0 是 1.0 以来的首个重大版本,带来了存算分离状态管理、物化表、批作业自适应执行等新特性。
思考与练习
-
用自己的话解释"无界数据流"与"有界数据流"的区别,并各举一个生活或业务中的例子。
-
什么是"有状态计算"?请举一个必须依赖状态才能完成的计算任务。
-
Flink 起源于哪个研究项目?它在哪一年成为 Apache 顶级项目?
-
阿里巴巴的 Blink 分支相比原生 Flink 的主要优势是什么?
第 2 章 Flink 核心架构
【学习目标】
说出 Flink 运行时的两类核心进程(JobManager、TaskManager)及其职责;
说出 JobManager 内部三个组件(ResourceManager、Dispatcher、JobMaster)的分工;
解释算子链(Operator Chain)的原理及其带来的性能收益;
解释任务槽(Task Slot)的作用以及 Slot 共享机制的优点;
比较 Session、Job、Application 三种部署模式在集群生命周期与资源隔离上的差异。
2.1 架构总览
Flink 是一个分布式系统,需要有效分配和管理计算资源才能执行流应用程序。它集成了所有常见的集群资源管理器,例如 Hadoop YARN、Kubernetes,但也可以设置为独立(Standalone)集群运行,甚至作为库嵌入到应用程序中。
本章概述 Flink 架构,并描述其主要组件如何交互以执行应用程序以及如何从故障中恢复。学习本章时,建议抓住一条主线:一个 Flink 程序,是如何从客户端提交,经过 JobManager 调度,最终在 TaskManager 的 Task Slot 中被执行的。
2.2 Flink 集群剖析:两类核心进程
Flink 运行时(Runtime)由两种类型的进程组成:一个 JobManager 和一个或者多个 TaskManager。

图 2-1 Flink 集群运行时架构
【读图提示】
左下角的 Flink Program / Client:用户程序经优化器/图构建器生成数据流图(Dataflow Graph),由 Client 提交给 JobManager;
右下角的 JobManager(Master / YARN Application Master):内含调度器(Scheduler)与 Checkpoint 协调器(Checkpoint Coordinator),负责部署、停止、取消任务以及触发 Checkpoint;
上方的 TaskManager(Worker):每个包含若干 Task Slot,真正运行 Task;TaskManager 之间直接交换数据流(Data Streams),并向 JobManager 汇报任务状态、心跳与统计信息。
可以通过多种方式启动 JobManager 和 TaskManager:直接在机器上作为 standalone 集群启动、在容器中启动、或者通过 YARN 等资源框架管理并启动。TaskManager 连接到 JobManager,宣布自己可用,并被分配工作。
2.2.1 Client:作业提交的入口
Client (客户端)不是运行时和程序执行的一部分,而是用于准备数据流并将其发送给 JobManager。之后,客户端可以断开连接(分离模式 ),或保持连接来接收进程报告(附加模式)。
客户端有两种运行形态:
-
作为触发执行的 Java/Scala 程序的一部分运行(例如在 IDE 中直接运行
main()方法); -
在命令行进程
./bin/flink run ...中运行。
2.2.2 JobManager:集群的"指挥中心"
JobManager 具有许多与协调 Flink 应用程序分布式执行有关的职责:
-
决定何时调度下一个 task(或一组 task);
-
对完成的 task 或执行失败做出反应;
-
协调 checkpoint;
-
协调从失败中恢复等等。
JobManager 进程由三个不同的组件组成:
| 组件 | 核心职责 | 补充说明 |
|---|---|---|
| ResourceManager | 负责 Flink 集群中的资源提供、回收、分配------它管理 task slots,这是 Flink 集群中资源调度的单位 | Flink 为不同的环境和资源提供者(例如 YARN、Kubernetes 和 standalone 部署)实现了对应的 ResourceManager。在 standalone 设置中,ResourceManager 只能分配可用 TaskManager 的 slots,而不能自行启动新的 TaskManager |
| Dispatcher | 提供一个 REST 接口,用来提交 Flink 应用程序执行,并为每个提交的作业启动一个新的 JobMaster | 它还运行 Flink WebUI,用来提供作业执行信息 |
| JobMaster | 负责管理单个 JobGraph 的执行 | Flink 集群中可以同时运行多个作业,每个作业都有自己的 JobMaster |
【高可用说明】 集群中始终至少有一个 JobManager。高可用(HA)设置中可能有多个 JobManager,其中一个始终是 leader ,其他的则是 standby (请参考高可用(HA))。
2.2.3 TaskManager:真正"干活"的工作进程
TaskManager (也称为 worker)执行作业流的 task,并且缓存和交换数据流。
-
必须始终至少有一个 TaskManager;
-
在 TaskManager 中,资源调度的最小单位是 task slot;
-
TaskManager 中 task slot 的数量表示并发处理 task 的数量;
-
注意:一个 task slot 中可以执行多个算子(详见 2.3 节"Tasks 和算子链")。
【类比记忆】 可以把 Flink 集群想象成一个软件项目团队:
Client 像提需求的客户,把需求(作业)交给项目经理后可以离开(分离模式),也可以留下来等结果(附加模式);
JobManager 像项目经理,负责拆解任务、分配工作、出错后安排重做(故障恢复);
TaskManager 像一线开发人员,领取任务并执行,定期汇报进度(心跳、状态);
Task Slot 像每位开发人员手头的"工位"数量,决定他能同时处理多少任务。
2.3 Tasks 与算子链
对于分布式执行,Flink 将算子(Operator)的 subtask 链接 (chain)成 tasks 。每个 task 由一个线程执行。
将算子链接成 task 是一个有用的优化:
-
减少了线程间切换和缓冲的开销;
-
在减少延迟的同时增加了整体吞吐量。
链行为是可以配置的,请参考链文档以获取详细信息。

图 2-2 算子链:精简视图(上)与并行视图(下)
【读图提示】
上半部分是精简视图:
Source与map()被链接为一个 task,keyBy()/window()/apply()为一个 task,Sink为一个 task;下半部分是并行视图:
Source/map()并行度为 2、keyBy()/window()/apply()并行度为 2、Sink并行度为 1,因此总共有 5 个 subtask ,对应 5 个并行线程。
【关键概念】并行度(Parallelism) 一个算子被拆分成多少个并行的 subtask,就称这个算子的并行度是多少。图 2-2 中
map()的并行度为 2,Sink的并行度为 1。
2.4 Task Slots 与资源管理
2.4.1 什么是 Task Slot
每个 worker(TaskManager)都是一个 JVM 进程 ,可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task,就有了所谓的 task slots(至少一个)。
每个 task slot 代表 TaskManager 中资源的固定子集。例如,具有 3 个 slot 的 TaskManager,会将其托管内存的 1/3 用于每个 slot。分配资源意味着 subtask 不会与其他作业的 subtask 竞争托管内存,而是具有一定数量的保留托管内存。
【注意】 此处没有 CPU 隔离;当前 slot 仅分离 task 的托管内存。

图 2-3 两个 TaskManager、每个拥有 3 个 Task Slot(未启用 Slot 共享时的任务分布)
2.4.2 Slot 数量与隔离程度
通过调整 task slot 的数量,用户可以定义 subtask 如何互相隔离:
| 配置方式 | 效果 |
|---|---|
| 每个 TaskManager 一个 slot | 每个 task 组都在单独的 JVM 中运行(例如可以在单独的容器中启动),隔离性最强 |
| 每个 TaskManager 多个 slot | 更多 subtask 共享同一 JVM。同一 JVM 中的 task 共享 TCP 连接(通过多路复用)和心跳信息,还可以共享数据集和数据结构,从而减少了每个 task 的开销 |
2.4.3 Slot 共享
默认情况下,Flink 允许 subtask 共享 slot,即便它们是不同 task 的 subtask,只要是来自于同一作业即可。结果就是一个 slot 可以持有整个作业管道。
允许 slot 共享有两个主要优点:
-
Flink 集群所需的 task slot 数量和作业中使用的最大并行度恰好一样,无需计算程序总共包含多少个 task(具有不同并行度)。
-
容易获得更好的资源利用 。如果没有 slot 共享,非密集型 subtask(
source/map())将阻塞和密集型 subtask(window)一样多的资源。通过 slot 共享,我们示例中的基本并行度从 2 增加到 6,可以充分利用分配的资源,同时确保繁重的 subtask 在 TaskManager 之间公平分配。

图 2-4 Slot 共享:并行度提升到 6 后,6 个 Slot 全部被利用,每个 Slot 持有一条完整的作业管道
【课堂提问】 对比图 2-3 与图 2-4:同样是 2 个 TaskManager、共 6 个 Slot,为什么图 2-3 中有一个 Slot 空闲,而图 2-4 中所有 Slot 都被利用?这体现了 Slot 共享的哪一条优点?
2.5 Flink 应用的执行与三种部署模式
2.5.1 Flink 应用程序的执行
Flink 应用程序 是从其 main() 方法产生的一个或多个 Flink 作业的任何用户程序。这些作业的执行可以在本地 JVM(LocalEnvironment)中进行,或在具有多台机器的集群的远程设置(RemoteEnvironment)中进行。对于每个程序,ExecutionEnvironment 提供了一些方法来控制作业执行(例如设置并行度)并与外界交互(请参考 Flink 程序剖析)。
Flink 应用程序的作业可以被提交到三类集群:
-
长期运行的 Flink Session 集群;
-
专用的 Flink Job 集群;
这些选项之间的差异主要与集群的生命周期 和资源隔离保证有关,下面分别介绍。
2.5.2 Flink Session 集群
-
集群生命周期:在 Flink Session 集群中,客户端连接到一个预先存在的、长期运行的集群,该集群可以接受多个作业提交。即使所有作业完成后,集群(和 JobManager)仍将继续运行,直到手动停止 session 为止。因此,Flink Session 集群的寿命不受任何 Flink 作业寿命的约束。
-
资源隔离:TaskManager slot 由 ResourceManager 在提交作业时分配,并在作业完成时释放。由于所有作业都共享同一集群,因此在集群资源方面存在一些竞争------例如提交作业阶段的网络带宽。此共享设置的局限性在于,如果 TaskManager 崩溃,则在此 TaskManager 上运行 task 的所有作业都将失败;类似的,如果 JobManager 上发生一些致命错误,它将影响集群中正在运行的所有作业。
-
其他注意事项:拥有一个预先存在的集群可以节省大量申请资源和启动 TaskManager 的时间。有种场景很重要:作业执行时间短,而启动时间长会对端到端的用户体验产生负面影响------就像对简短查询的交互式分析一样,希望作业可以使用现有资源快速执行计算。
以前,Flink Session 集群也被称为 session 模式下的 Flink 集群。
2.5.3 Flink Job 集群
-
集群生命周期:在 Flink Job 集群中,可用的集群管理器(例如 YARN)用于为每个提交的作业启动一个集群,并且该集群仅可用于该作业。在这里,客户端首先从集群管理器请求资源启动 JobManager,然后将作业提交给在这个进程中运行的 Dispatcher;然后根据作业的资源请求惰性地分配 TaskManager。一旦作业完成,Flink Job 集群将被拆除。
-
资源隔离:JobManager 中的致命错误仅影响在 Flink Job 集群中运行的这一个作业。
-
其他注意事项 :由于 ResourceManager 必须申请并等待外部资源管理组件来启动 TaskManager 进程和分配资源,因此 Flink Job 集群更适合长期运行、具有高稳定性要求且对较长的启动时间不敏感的大型作业。
2.5.4 Flink Application 集群
-
集群生命周期 :Flink Application 集群是专用的 Flink 集群,仅从一个 Flink 应用程序执行作业,并且
main()方法在集群上而不是客户端上运行 。提交作业是一个单步骤过程:无需先启动 Flink 集群、再将作业提交到现有的 session 集群;相反,将应用程序逻辑和依赖打包成一个可执行的作业 JAR,并且集群入口(ApplicationClusterEntryPoint)负责调用main()方法来提取 JobGraph。例如,这允许你像在 Kubernetes 上部署任何其他应用程序一样部署 Flink 应用程序。因此,Flink Application 集群的寿命与 Flink 应用程序的寿命有关。 -
资源隔离:在 Flink Application 集群中,ResourceManager 和 Dispatcher 作用于单个的 Flink 应用程序,相比于 Flink Session 集群,它提供了更好的隔离。
Flink Job 集群可以看做是 Flink Application 集群"客户端运行"的替代方案。
2.5.5 三种部署模式对比
| 对比维度 | Session 集群 | Job 集群 | Application 集群 |
|---|---|---|---|
| 集群生命周期 | 长期运行,与作业无关;作业全部结束后仍运行,直到手动停止 | 每个作业独享一个集群,作业结束即拆除 | 与应用程序的生命周期一致 |
| 资源隔离 | 弱:所有作业共享集群,TaskManager 或 JobManager 故障会波及所有作业 | 强:JobManager 故障只影响该作业 | 较强:ResourceManager 与 Dispatcher 只服务于单个应用 |
main() 执行位置 |
客户端 | 客户端 | 集群(由 ApplicationClusterEntryPoint 调用) |
| 提交流程 | 先有集群,再提交作业 | 先向集群管理器申请资源启动集群,再提交作业 | 应用与依赖打包成一个 JAR,一步提交 |
| 启动开销 | 低(复用已有资源,响应快) | 高(需等待外部资源管理组件分配资源) | 中 |
| 典型适用场景 | 执行时间短、对启动延迟敏感的作业,如交互式查询分析 | 长期运行、稳定性要求高、对启动时间不敏感的大型作业 | 容器化环境(如 Kubernetes)中像部署普通应用一样部署 Flink 应用 |
【选型口诀】 短作业、快响应用 Session ;大作业、要隔离用 Job ;上 Kubernetes、一步部署用 Application。
本章小结
-
Flink 运行时由一个 JobManager 和一个或多个 TaskManager 组成;Client 负责提交作业,不属于运行时;
-
JobManager 内部包含 ResourceManager (管 slot 资源)、Dispatcher (接收提交、运行 WebUI)、JobMaster(管单个作业)三个组件;
-
TaskManager 以 task slot 为资源调度的最小单位,slot 数量即并发处理 task 的数量;slot 只隔离托管内存,不隔离 CPU;
-
算子链把多个算子的 subtask 链接到一个线程中执行,减少切换与缓冲开销,降低延迟、提高吞吐;
-
Slot 共享让一个 slot 可以持有整条作业管道,使集群所需 slot 数等于作业最大并行度,并提高资源利用率;
-
三种部署模式的核心差异在于集群生命周期 与资源隔离 :Session 共享集群,Job 一作业一集群,Application 一应用一集群且
main()在集群上运行。
思考与练习
-
Flink 集群包含哪两类进程?分别承担什么职责?
-
JobManager 内部的三个组件分别是什么?WebUI 由哪个组件提供?
-
什么是算子链?Flink 为什么要把算子链接成 task?
-
一个作业中
source/map()并行度为 2、window并行度为 6、sink并行度为 1。在默认开启 slot 共享的情况下,集群至少需要多少个 task slot?如果关闭 slot 共享呢? -
团队需要在 Kubernetes 上长期运行多个相互独立的流作业,并希望某个作业出故障时不影响其他作业,你会选择哪种部署模式?说明理由。
第 3 章 Flink API 分层
【学习目标】
说出 Flink API 由低到高的四层抽象及其名称;
描述每一层抽象的特点、表达能力与典型适用场景;
理解各层之间的关系(如 Process Function 与 DataStream API 的集成、Table API 与 SQL 的关系);
能够根据业务需求选择合适的 API 层级。
3.1 API 分层总览
Flink 为开发者提供了四层逐级抽象的编程接口,如图 3-1 所示。

图 3-1 Flink API 的四层抽象
理解这张图的要点是:越往下,越灵活、越贴近底层细节,但开发成本越高;越往上,越简洁、越贴近业务表达,并且可以享受优化器带来的性能收益。
| 层级 | 名称 | 一句话定位 |
|---|---|---|
| 第 4 层(最顶层) | SQL | 用标准 SQL 表达计算逻辑,使用门槛最低 |
| 第 3 层 | Table API | 以"表"为中心的声明式 DSL |
| 第 2 层 | Core APIs(DataStream API) | 通用模块组件,大多数应用的首选 |
| 第 1 层(最底层) | 有状态实时流处理(Process Function) | 底层构建块,可精细控制流、状态与时间 |
下面自底向上逐层讲解。
3.2 第一层:有状态实时流处理(Process Function)
Flink API 最底层的抽象为有状态实时流处理 。其抽象实现是 Process Function,并且 Process Function 被 Flink 框架集成到了 DataStream API 中来为我们使用。
这一层的能力特点:
-
允许用户在应用程序中自由地处理来自单流或多流的事件(数据);
-
提供具有全局一致性 和容错保障 的状态;
-
用户可以在此层抽象中注册事件时间(event time) 和**处理时间(processing time)**回调方法,从而允许程序实现复杂计算。
【理解要点】 这一层把流处理的三大核心要素------流(streams)、状态(state)、时间(time)------完全暴露给开发者,因此最灵活,也最"重"。它适合实现上层 API 难以表达的复杂逻辑,例如基于定时器的超时检测。
3.3 第二层:Core APIs(DataStream API)
Flink API 第二层抽象是 Core APIs 。实际上,许多应用程序不需要使用到上述最底层抽象的 API,而是可以使用 Core APIs 进行编程:其中包含 DataStream API(应用于有界/无界数据流场景)。
Core APIs 提供的流式 API(Fluent API)为数据处理提供了通用的模块组件,例如:
-
各种形式的用户自定义转换(transformations);
-
联接(joins);
-
聚合(aggregations);
-
窗口(windows);
-
状态(state)操作等。
此层 API 中处理的数据类型在每种编程语言中都有其对应的类。
【层间关系】 Process Function 这类底层抽象和 DataStream API 的相互集成,使得用户可以在 DataStream 程序中按需"下沉"到更底层的抽象 API 来实现自己的需求。换句话说,第一层与第二层不是割裂的,而是可以在同一个程序中搭配使用。
3.4 第三层:Table API
Flink API 第三层抽象是 Table API 。Table API 是以表(Table)为中心的声明式 编程(DSL)API,例如在流式数据场景下,它可以表示一张正在动态改变的表。
Table API 遵循(并扩展)关系模型:
-
表拥有 schema(类似于关系型数据库中的 schema);
-
提供了类似于关系模型中的操作,比如
select、project、join、group-by和aggregate等。
Table API 程序是以声明的方式定义应执行的逻辑操作 ,而不是确切地指定程序应该执行的代码 。尽管 Table API 使用起来很简洁,并且可以由各种类型的用户自定义函数扩展功能,但还是比 Core API 的表达能力差 。此外,Table API 程序在执行之前还会使用优化器中的优化规则对用户编写的表达式进行优化。
【层间关系】 表和 DataStream 可以进行无缝切换,Flink 允许用户在编写应用程序时将 Table API 与 DataStream API 混合使用。
3.5 第四层:SQL
Flink API 最顶层抽象是 SQL 。这层抽象在语义和程序表达式上都类似于 Table API ,但是其程序实现都是 SQL 查询表达式。
SQL 抽象与 Table API 抽象之间的关联是非常紧密的,并且 SQL 查询语句可以在 Table API 中定义的表上执行。
【理解要点】 Table API 与 SQL 可以看作"一体两面":二者共享同一套表的概念、同一个优化器和执行引擎,只是书写形式不同------一个用链式方法调用,一个用 SQL 语句。这也是第 1 章提到 Blink 对 SQL 的增强能同时惠及这两层的原因。
3.6 四层 API 对比与选型建议
| 对比维度 | Process Function | DataStream API | Table API | SQL |
|---|---|---|---|---|
| 编程风格 | 命令式,逐事件处理 | 命令式,链式算子 | 声明式 DSL | 声明式 SQL |
| 表达能力 | 最强 | 强 | 中 | 中 |
| 开发效率 | 低 | 中 | 高 | 最高 |
| 是否经优化器优化 | 否 | 否 | 是 | 是 |
| 对时间/状态的控制粒度 | 最细(定时器、底层状态) | 较细(窗口、状态 API) | 粗 | 粗 |
| 典型使用者 | 高级开发者 | 应用开发者 | 应用开发者 / 数据工程师 | 数据分析师 / 所有人 |
选型建议:
| 你的需求 | 推荐层级 |
|---|---|
| 常规 ETL、指标聚合、报表统计,团队熟悉 SQL | SQL 或 Table API |
| 常规流处理应用:转换、过滤、窗口、聚合、双流 join | DataStream API |
| 需要精细控制事件时间、自定义定时器、直接操作底层状态 | Process Function |
| 大部分逻辑用上层 API 表达,个别复杂逻辑需要下沉 | 混合使用:Table API ⇄ DataStream API 无缝切换,DataStream 中嵌入 Process Function |
【经验法则】 能用上层 API 解决的,就不要用下层 API。上层 API 代码更少、更易维护,还能自动获得优化器的优化;只有在上层 API 表达不了时,才下沉一层。
本章小结
-
Flink API 由低到高分为四层:有状态实时流处理(Process Function)→ Core APIs(DataStream API)→ Table API → SQL;
-
越底层越灵活、控制越细;越顶层越简洁、门槛越低,并可被优化器优化;
-
Process Function 集成在 DataStream API 中,二者可搭配使用;Table API 与 DataStream API 可无缝切换、混合使用;SQL 与 Table API 语义相近、紧密关联;
-
选型原则:优先使用能满足需求的最高层 API。
思考与练习
-
请按从低到高的顺序写出 Flink API 的四层抽象名称,并各用一句话概括其特点。
-
为什么说 Process Function 是"最灵活但最重"的一层?它暴露了流处理的哪三大核心要素?
-
Table API 与 SQL 是什么关系?为什么说它们是"一体两面"?
-
以下场景分别适合用哪一层 API?说明理由:
-
(a)统计每 5 分钟各商品类目的销售额;
-
(b)检测用户下单后 30 分钟内未支付则发送提醒;
-
(c)将 Kafka 中的 JSON 日志清洗后写入 HDFS。
-
第 4 章 Flink 集群部署实战
【学习目标】
完成 Flink 2.3.0 安装包的下载与前置环境检查;
独立完成 Standalone 集群的解压、环境变量配置、配置文件修改与多节点分发;
掌握集群的启动方法,并能通过 WebUI 验证集群状态;
能对常见的启动失败问题进行初步排查。
4.1 部署规划与环境准备
4.1.1 集群规划
本次实训部署一个 3 节点的 Standalone 集群,节点角色规划如下:
| 节点 | 角色 | 说明 |
|---|---|---|
| node11 | JobManager(Master) | 运行 WebUI,端口 8081 |
| node12 | TaskManager(Worker) | 执行 task |
| node13 | TaskManager(Worker) | 执行 task |
回顾第 2 章:JobManager 负责调度与协调,TaskManager 负责执行。本章的配置文件
masters与workers正是分别用来声明这两类进程所在的节点。
4.1.2 前置环境
在开始安装前,请确认以下环境已就绪:
| 前置条件 | 要求 | 说明 |
|---|---|---|
| Java 环境 | Java 17 | Flink 2.x 的配置文件中包含 Java 17 所需的 --add-opens 等 JVM 参数(配置注释原文:These parameters are required for Java 17 support. They can be safely removed when using Java 8/11. )。安装参考:Linux环境下Java17环境安装-CSDN博客 |
| 主机名解析 | 三台节点的 /etc/hosts 中均配置 node11、node12、node13 的 IP 映射 |
节点间通过主机名互相访问 |
| SSH 免密登录 | node11 可免密登录 node12、node13 | start-cluster.sh 需要通过 SSH 远程启动 TaskManager |
| Hadoop 集群(可选) | 已安装并可正常启动 | 本实训在启动 Flink 前先启动 Hadoop |
4.2 下载安装包
国内推荐使用阿里云镜像站下载,速度更快:
apache-flink-flink-2.3.0 安装包下载 - 开源镜像站 - 阿里云

图 4-1 阿里云镜像站 Flink 2.3.0 下载页面
选择 flink-2.3.0-bin-scala_2.12.tgz 下载,并上传到 node11 的 /usr/local/soft/ 目录。
4.3 安装与配置(在 node11 上操作)
步骤 1:解压安装包
cd /usr/local/soft/
tar -zxvf flink-2.3.0-bin-scala_2.12.tgz
步骤 2:配置环境变量
编辑系统环境变量文件:
vim /etc/profile
在文件末尾追加以下内容:
#flink
export FLINK_HOME=/usr/local/soft/flink-2.3.0
export PATH=$PATH:$FLINK_HOME/bin
使配置立即生效:
source /etc/profile
步骤 3:修改配置文件
Flink 的配置文件位于 $FLINK_HOME/conf/ 目录下,本次需要修改三个文件。
(1)修改 config.yaml
文件路径:/usr/local/soft/flink-2.3.0/conf/config.yaml。找到 jobmanager 配置段,修改两处:
jobmanager:
bind-host: 0.0.0.0 # 参数 jobmanager.bind-host
rpc:
address: node11 # 参数 jobmanager.rpc.address
port: 6123

图 4-2 config.yaml 中需要修改的两处(红框所示)
【注意】 Flink 2.x 的
config.yaml采用标准 YAML 的层级缩进 写法。jobmanager.rpc.address这种"点分"名称是参数的完整键名,在文件中对应jobmanager:→rpc:→address:的三级缩进结构,不要直接写成一行。缩进必须使用空格,不能使用 Tab。
两个参数的含义:
| 参数 | 作用 |
|---|---|
jobmanager.bind-host |
JobManager 绑定的网络接口。默认 localhost 只能本机访问;改为 0.0.0.0 表示监听所有网卡,以便 TaskManager 和浏览器从其他机器访问 |
jobmanager.rpc.address |
JobManager 所在主机的对外地址,TaskManager 和客户端通过它连接 JobManager。Standalone 模式下必须正确设置 |
(2)修改 masters 文件
声明 JobManager 所在节点及 WebUI 端口:
node11:8081
(3)修改 workers 文件
声明 TaskManager 所在节点,每行一个:
node12
node13
步骤 4:分发到其他节点
将配置好的 Flink 目录和环境变量文件远程拷贝到 node12、node13:
scp -r /usr/local/soft/flink-2.3.0 root@node12:/usr/local/soft
scp -r /usr/local/soft/flink-2.3.0 root@node13:/usr/local/soft
scp /etc/profile root@node12:/etc/profile
scp /etc/profile root@node13:/etc/profile
分别登录 node12、node13,使环境变量生效:
source /etc/profile
步骤 5:启动集群
先启动 Hadoop 集群:
start-all.sh
再启动 Flink 集群(在 node11 上执行):
start-cluster.sh
【小知识】
start-cluster.sh会读取masters文件在对应节点启动 JobManager,读取workers文件通过 SSH 在各节点启动 TaskManager------这就是为什么需要提前配置 SSH 免密登录。对应的停止命令是stop-cluster.sh。
步骤 6:验证集群
在浏览器中输入 WebUI 地址:http://node11:8081
验证要点:
-
能正常打开 Flink WebUI 首页(Overview);
-
Task Managers 数量为 2 (对应
workers文件中的 node12、node13); -
Available Task Slots 大于 0,说明集群已具备运行作业的资源。
也可以在各节点执行 jps 命令查看 Java 进程:node11 上应有 JobManager 进程(StandaloneSessionClusterEntrypoint),node12、node13 上应有 TaskManager 进程(TaskManagerRunner)。
4.4 常见问题排查
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
执行 start-cluster.sh 提示找不到 Java 或版本不符 |
Java 17 未安装或 JAVA_HOME 未配置 |
各节点执行 java -version 检查版本;确认 /etc/profile 中的 JAVA_HOME 并已 source |
| WebUI 打不开 | JobManager 未启动、8081 端口被防火墙拦截、访问机器的 hosts 未配置 node11 | node11 执行 jps 查看 JobManager 进程;检查防火墙与 hosts 配置 |
| WebUI 中 Task Managers 为 0 或少于 2 | workers 文件写错、SSH 免密未配置、jobmanager.rpc.address 设置错误导致 TaskManager 连不上 |
查看 $FLINK_HOME/log/ 下 TaskManager 相关日志;在 node12、node13 上执行 jps |
某节点上 flink 命令不可用 |
环境变量未分发或未生效 | 在该节点执行 source /etc/profile |
| 修改配置文件后不生效 | YAML 缩进错误(使用了 Tab 或层级不对) | 对照图 4-2 检查缩进,统一使用空格 |
本章小结
-
Standalone 集群部署的核心是六步:解压 → 配置环境变量 → 修改配置文件 → 分发到其他节点 → 启动集群 → 验证;
-
三个关键配置:
config.yaml中设置jobmanager.bind-host与jobmanager.rpc.address,masters声明 JobManager 节点,workers声明 TaskManager 节点; -
Flink 2.x 需要 Java 17 环境;
config.yaml使用层级缩进的 YAML 格式,参数以点分名称书写; -
通过 WebUI(node11:8081) 和
jps命令验证集群状态。
实训任务
-
基础任务 :按本章步骤独立完成 3 节点 Flink 集群的部署,提交 WebUI Overview 页面截图以及三个节点的
jps输出截图。 -
进阶任务 :修改
workers文件,把 node11 也加入 TaskManager 列表,重启集群后观察 WebUI 中 Task Managers 与 Task Slots 数量的变化,并解释原因。 -
拓展任务 :Flink 发行包的
examples目录中自带示例程序(如 WordCount),尝试使用flink run命令提交一个示例作业,并在 WebUI 中观察作业的运行状态与各 task 的并行度。
附录 术语速查表
| 术语 | 英文 | 含义 |
|---|---|---|
| 无界数据流 | Unbounded Stream | 有起点、无终点、持续产生的数据流 |
| 有界数据流 | Bounded Stream | 有明确起止的数据集,可视为有限长度的流 |
| 有状态计算 | Stateful Computation | 计算过程中需要保存并利用历史信息(状态)的计算 |
| 作业管理器 | JobManager | 集群主进程,负责调度、Checkpoint 协调与故障恢复 |
| 任务管理器 | TaskManager | 集群工作进程(worker),负责执行 task、缓存与交换数据 |
| 资源管理器 | ResourceManager | JobManager 组件,负责 task slot 的分配与回收 |
| 分发器 | Dispatcher | JobManager 组件,提供 REST 提交接口与 WebUI,为作业创建 JobMaster |
| 作业主控 | JobMaster | JobManager 组件,负责管理单个作业(JobGraph)的执行 |
| 任务槽 | Task Slot | TaskManager 中资源调度的最小单位,隔离托管内存 |
| 算子 | Operator | 数据流上的一个计算步骤,如 map、keyBy、window |
| 子任务 | Subtask | 算子的一个并行实例 |
| 算子链 | Operator Chain | 将多个算子的 subtask 链接到同一线程执行的优化 |
| 并行度 | Parallelism | 一个算子被拆分为多少个并行 subtask |
| 作业图 | JobGraph | 作业的逻辑数据流图 |
| 检查点 | Checkpoint | Flink 的容错机制,定期对状态做一致性快照 |
| 三种部署模式 | Session / Job / Application Cluster | Flink 的三种集群形态,区别在于集群生命周期与资源隔离 |