第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 运行时架构。每次给团队新人讲架构,我都先画这张图。

Flink 运行时架构 Flink Client JobManager 调度 / Checkpoint 协调 TaskManager 1 Slot 1 | Slot 2 Slot 3 | Slot 4 TaskManager 2 Slot 1 | Slot 2 Slot 3 | Slot 4 TaskManager 3 Slot 1 | Slot 2 Slot 3 | Slot 4 Kafka / 数据源 Elasticsearch / 输出 说明: Client 提交作业 → JobManager 生成执行计划 → 分发到 TaskManager 的 Slot 中执行 每个 TaskManager 是一个 JVM 进程,Slot 是资源隔离单元

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 入门最难的其实是理解它的设计思想——一切皆流。后面的章节我们会在这个基础上,一步步深入状态管理、时间语义、窗口计算这些核心概念。到时候你会发现,今天搭的这个环境,就是你探索实时计算世界的起点。