第3章 Flink入门:从历史到实战搭建
说实话,Flink 现在已经是实时计算领域的事实标准了。但你知道吗?它刚诞生的时候,连个像样的中文文档都没有。我2016年第一次接触 Flink,翻着英文社区帖子搭环境,踩了不少坑。今天这一章,我就把那些经验掰开揉碎讲给你听。
3.1 Flink 发展史:从学术项目到工业标配
Flink 的故事要从 2008 年说起。那时候大数据领域还是 Hadoop 的天下,批处理是主流。但柏林工业大学的一群研究者觉得:为什么不能有一套系统,既能做批处理,又能做流处理?
于是他们启动了 Stratosphere 项目——这就是 Flink 的前身。
| 时间 | 里程碑事件 | 我的观察 |
|---|---|---|
| 2008-2010 | Stratosphere 项目启动,研究流批一体架构 | 当时大多数人还在玩 MapReduce |
| 2014 | Flink 成为 Apache 顶级项目 | 我那年刚入行,完全没注意到它 |
| 2015 | 阿里巴巴开始大规模使用 Flink | 国内实时计算从此起飞 |
| 2019 | Flink 1.9 发布,Blink 合并回社区 | 阿里巴巴把内部优化全部开源,太狠了 |
| 2023 | Flink 1.17,流批一体全面成熟 | 现在新项目我基本无脑选 Flink |
为什么 Flink 能赢?说白了就两个词:低延迟和状态一致性。Storm 延迟低但状态管理弱,Spark Streaming 吞吐高但延迟做不到毫秒级。Flink 把这两者都做到了。
核心认知:Flink 不是批处理系统改的流处理,它天生就是为流而生。批处理只是流的一个特例——有限流。这个设计哲学让它比任何「批改流」的系统都优雅。
3.2 Flink 核心特性:凭什么选它?
我经常被问到:「Flink 和 Spark Streaming 到底怎么选?」嗯,这个问题我回答过不下 50 次。先看看 Flink 的硬核能力:
3.2.1 真正的流处理引擎
Flink 处理每条数据都是「来一条处理一条」,而不是攒一批再处理。这就像餐厅里,一个是来一个客人就做菜(Flink),另一个是等凑满一桌再做(Spark)。你想想看,哪个体验更好?
3.2.2 精确一次语义(Exactly-Once)
这是 Flink 的杀手锏。我做过一个金融风控项目,数据必须不重不丢。Flink 的 checkpoint 机制配合两阶段提交,保证了即使机器宕机,恢复后数据也完全一致。
避坑指南:我曾经以为开了 checkpoint 就万事大吉,结果发现 Kafka 的 offset 提交和 Flink 的 checkpoint 没对齐,导致重启后重复消费。后来统一用 Flink 的 Kafka Connector 自带语义才解决。
3.2.3 事件时间处理
数据到达时间和事件发生时间往往是两回事。比如用户凌晨 1 点下单,网络延迟到凌晨 2 点才到服务器。Flink 的事件时间机制能正确处理这种乱序数据。我做过一个电商大屏项目,如果不处理事件时间,凌晨的订单会跑到白天的统计里,那数据就全乱了。
3.2.4 状态管理与容错
Flink 把状态保存在内存或 RocksDB 中,通过 checkpoint 定期快照。一旦失败,从最近一次 checkpoint 恢复。状态后端支持多种存储:
| 状态后端 | 存储位置 | 适用场景 |
|---|---|---|
| MemoryStateBackend | JVM 堆内存 | 开发调试,小状态 |
| FsStateBackend | 文件系统(HDFS/S3) | 生产环境,中等状态 |
| RocksDBStateBackend | 本地磁盘 + 文件系统 | 超大状态(TB 级) |
3.3 Flink 架构与组件:一张图看懂
下面这张图是我自己画的 Flink 运行时架构。每次给团队新人讲架构,我都先画这张图。
3.3.1 核心组件说明
- JobManager:集群的「大脑」。负责接收作业、生成执行计划、协调 checkpoint。我遇到过 JobManager 单点故障导致整个集群不可用的情况,后来用 Standby JobManager 做高可用才解决。
- TaskManager:真正干活的「工人」。每个 TaskManager 有多个 Slot,Slot 是资源调度的最小单位。一个 Slot 可以运行一个线程。
- Client:提交作业的入口。把作业打包成 Jar 包,提交给 JobManager。我习惯在本地开发时用命令行提交,生产环境用 Flink REST API 自动化部署。
3.4 Flink 环境搭建:手把手带你跑起来
理论说完了,咱们动手。我建议你在本地先搭一个单机版 Flink,跑通第一个 WordCount 作业。这是最快建立手感的方式。
3.4.1 前置条件
- JDK 8 或 11(我推荐 JDK 11,性能更好)
- Maven 3.x(用于编译 Java 作业)
- Linux/MacOS(Windows 也能跑,但坑多,我建议用 WSL2)
3.4.2 下载与启动
# 下载 Flink 1.17.0(写本文时最新稳定版)
wget https://dlcdn.apache.org/flink/flink-1.17.0/flink-1.17.0-bin-scala_2.12.tgz
# 解压
tar -xzf flink-1.17.0-bin-scala_2.12.tgz
cd flink-1.17.0
# 启动本地集群
./bin/start-cluster.sh
# 检查是否启动成功
jps
# 应该看到:StandaloneSessionClusterEntrypoint 和 TaskManagerRunner
注意:启动前确保 8081 端口没有被占用。Flink Web UI 默认跑在 8081 端口。我曾经因为 Jenkins 占用了 8081,排查了半天才发现。
3.4.3 提交第一个作业
Flink 自带了几个示例作业,咱们先跑一个 WordCount:
# 提交 WordCount 作业
./bin/flink run ./examples/batch/WordCount.jar
# 查看输出(默认输出到 TaskManager 的日志)
tail -f ./log/flink-*-taskexecutor-*.out
你会看到类似这样的输出:
(hello, 3)
(flink, 2)
(world, 1)
...
嗯,第一个作业跑通了。这时候打开浏览器访问 http://localhost:8081,你会看到 Flink Web UI。这里能看到作业的运行状态、TaskManager 的资源使用情况、checkpoint 历史等。我平时排查问题,90% 的时间都泡在这个 UI 上。
3.4.4 配置调优建议
单机版默认配置比较保守。我建议你至少改这几个参数:
| 配置项 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
| taskmanager.numberOfTaskSlots | 1 | 4 | 提高并行度,充分利用 CPU |
| taskmanager.memory.process.size | 1728m | 4096m | 给 TaskManager 更多内存 |
| jobmanager.memory.process.size | 1728m | 2048m | JobManager 内存,一般不用太大 |
| parallelism.default | 1 | 2 | 默认并行度,根据核数调整 |
配置文件在 conf/flink-conf.yaml。改完重启集群生效。
我的习惯:本地开发时把 parallelism.default 设成 2,既能测试并行逻辑,又不会把笔记本跑死。生产环境再根据集群规模调整。
3.5 本章小结
这一章我们从 Flink 的历史讲到了环境搭建。你知道了 Flink 为什么能成为实时计算的首选,理解了它的核心架构——JobManager 负责调度,TaskManager 负责执行,Slot 是资源单元。最后亲手跑通了第一个 WordCount 作业。
说实话,Flink 入门最难的其实是理解它的设计思想——一切皆流。后面的章节我们会在这个基础上,一步步深入状态管理、时间语义、窗口计算这些核心概念。到时候你会发现,今天搭的这个环境,就是你探索实时计算世界的起点。