一、Flink 是什么
Apache Flink 是一个面向有界流和无界流的分布式计算引擎,核心定位是「以流为核心,批是流的一种特例」。它提供低延迟、高吞吐、Exactly-Once 语义的状态计算能力,广泛应用于实时数仓、实时风控、实时推荐、日志监控等场景。
理解 Flink 可以从三个关键词入手:
- 流式优先:所有计算都抽象为流,批处理只是有界流的特化。
- 有状态:算子可以维护状态,状态是 Flink 实现复杂业务逻辑的基础。
- 事件驱动:基于事件时间处理乱序数据,保证结果正确性。
二、Flink 整体架构
2.1 运行时组件
| 组件 | 职责 |
|---|---|
| JobManager | 作业调度、检查点协调、资源申请,是集群的「大脑」 |
| TaskManager | 实际执行任务的 Worker,管理 Slot 和内存资源 |
| Dispatcher | 接收作业提交,启动 JobManager |
| ResourceManager | 负责 Slot 的分配与回收 |
2.2 作业执行流程
flowchart LR
A[用户提交作业] --> B[Dispatcher]
B --> C[JobManager]
C --> D[生成 ExecutionGraph]
D --> E[ResourceManager 申请 Slot]
E --> F[TaskManager 执行 Task]
F --> G[Checkpoint 协调]
G --> H[结果输出]
一个 Flink 作业从提交到运行,大致经历:逻辑图(StreamGraph)→ 作业图(JobGraph)→ 执行图(ExecutionGraph)→ 物理执行四个阶段。
三、核心概念
3.1 DataStream API
DataStream 是 Flink 最核心的编程抽象,常见算子包括:
- map / flatMap / filter:无状态转换算子。
- keyBy:按 key 分区,是使用 Keyed State 的前提。
- window:对无限流做有界聚合。
- connect / union / join:多流合并与关联。
- process:最底层的处理算子,可访问时间戳、水位线和状态。
3.2 时间语义
| 时间类型 | 说明 |
|---|---|
| Event Time | 事件真实发生时间,最常用,能正确处理乱序 |
| Ingestion Time | 数据进入 Flink 的时间 |
| Processing Time | 算子处理时的系统时间,性能最好但结果不确定 |
3.3 水位线(Watermark)
Watermark 是 Flink 处理乱序数据的核心机制,本质是一个时间戳,表示「事件时间小于该值的数据已经全部到达」。常见生成策略:
- 周期性 Watermark:按固定间隔生成,适合大多数场景。
- 断点式 Watermark:根据特定标记生成,适合数据源自带边界信息。
- 空闲分区处理:通过
withIdleness避免空闲分区拖慢整体水位线。
四、状态管理与容错
4.1 状态类型
- Keyed State:与 key 绑定,只能在 keyBy 之后使用,包括 ValueState、ListState、MapState、ReducingState、AggregatingState。
- Operator State:与算子实例绑定,常用于 Source/Sink,如 ListState、BroadcastState。
4.2 状态后端
| 状态后端 | 特点 |
|---|---|
| HashMapStateBackend | 状态存于 JVM 堆内存,读写快,受内存限制 |
| EmbeddedRocksDBStateBackend | 状态存于本地 RocksDB,支持超大状态,可增量 Checkpoint |
4.3 Checkpoint 与 Savepoint
Checkpoint 是 Flink 实现 Exactly-Once 的关键,基于 Chandy-Lamport 算法的异步屏障快照机制:
- JobManager 周期性向 Source 注入 Barrier。
- Barrier 随数据流向下游传递,算子收到 Barrier 后对齐并做本地快照。
- 所有算子完成快照后,JobManager 记录本次 Checkpoint 元数据。
- 故障恢复时从最近一次成功的 Checkpoint 重放。
Savepoint 与 Checkpoint 机制类似,但由用户手动触发,常用于版本升级、扩缩容和迁移。
五、窗口机制
5.1 窗口类型
- 滚动窗口(Tumbling Window):固定大小、不重叠。
- 滑动窗口(Sliding Window):固定大小、可重叠。
- 会话窗口(Session Window):按活动间隙划分。
- 全局窗口(Global Window):需自定义 Trigger。
5.2 窗口组成
一个完整窗口由 Window Assigner + Trigger + Evictor + 窗口函数 四部分组成。窗口函数分为增量聚合(ReduceFunction、AggregateFunction)和全量聚合(ProcessWindowFunction),前者性能更好,后者可访问窗口元信息。
5.3 迟到数据处理
- allowedLateness:允许数据迟到一段时间,窗口延迟销毁。
- sideOutputLateData:将超迟数据输出到侧输出流单独处理。
六、容错与一致性
6.1 端到端 Exactly-Once
要实现端到端 Exactly-Once,需要 Source、内部计算、Sink 三部分共同保证:
- Source:支持可重放,如 Kafka 记录 offset。
- 内部:Checkpoint 保证状态一致性。
- Sink:支持事务或幂等写入,如 Kafka 两阶段提交、幂等写入数据库。
6.2 两阶段提交 Sink
public class TwoPhaseCommitSink extends TwoPhaseCommitSinkFunction<String, Transaction, Void> {
public TwoPhaseCommitSink() {
super(new SimpleStringSchema(), new TransactionSerializer());
}
@Override
protected Transaction beginTransaction() {
return new Transaction();
}
@Override
protected void invoke(Transaction transaction, String value, Context context) {
transaction.add(value);
}
@Override
protected void preCommit(Transaction transaction) {
transaction.flush();
}
@Override
protected void commit(Transaction transaction) {
transaction.commit();
}
@Override
protected void abort(Transaction transaction) {
transaction.rollback();
}
}
七、内存管理与性能调优
7.1 内存模型
Flink 1.10 之后采用统一内存模型,TaskManager 内存主要分为:
- JVM Metaspace:类元数据。
- JVM Overhead:JVM 自身开销。
- Framework Heap/Memory:Flink 框架自身使用。
- Task Heap/Memory:用户代码和算子使用。
- Managed Memory:由 Flink 管理,用于排序、哈希表、RocksDB。
- Network Memory:网络传输缓冲区。
7.2 常见调优方向
| 方向 | 建议 |
|---|---|
| 并行度 | 结合数据量和 Slot 数设置,避免数据倾斜 |
| 状态大小 | 大状态使用 RocksDB + 增量 Checkpoint |
| 网络缓冲 | 调整 taskmanager.network.memory 相关参数 |
| 反压 | 通过 Flink UI 定位瓶颈算子,优化下游写入 |
| 数据倾斜 | 加盐、两阶段聚合、自定义分区器 |
八、Flink SQL 与 Table API
Flink SQL 让流批统一开发成为可能,核心概念包括:
- 动态表(Dynamic Table):流与表之间的转换桥梁。
- 持续查询(Continuous Query):对动态表不断产生新结果。
- 时态表(Temporal Table):用于维表关联,支持处理时间和事件时间版本。
- CDC:通过 Flink CDC 直接捕获数据库变更,实现实时同步。
CREATE TABLE orders (
order_id STRING,
user_id STRING,
amount DECIMAL(10, 2),
order_time TIMESTAMP(3),
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'orders',
'properties.bootstrap.servers' = 'localhost:9092',
'format' = 'json'
);
SELECT
TUMBLE_START(order_time, INTERVAL '1' MINUTE) AS window_start,
user_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY TUMBLE(order_time, INTERVAL '1' MINUTE), user_id;
九、部署与运维
9.1 部署模式
- Session 模式:共享集群,适合小作业和交互式开发。
- Per-Job 模式:一个作业一个集群,资源隔离好(1.15 后逐步被 Application 模式取代)。
- Application 模式:main 方法在集群执行,适合生产环境。
9.2 高可用
生产环境通常配置 ZooKeeper 或 Kubernetes HA,将 JobManager 元数据和 Checkpoint 持久化到 HDFS/S3,实现故障自动恢复。
9.3 监控指标
- Checkpoint 相关:持续时间、大小、失败次数。
- 反压指标:backPressureLevel、inPoolUsage。
- 资源指标:CPU、内存、GC 时间。
- 业务指标:通过 Metrics 上报到 Prometheus + Grafana。
十、常见问题与最佳实践
10.1 常见问题
- Checkpoint 超时:检查反压、状态大小、网络和存储性能。
- 数据倾斜:定位热点 key,采用加盐或两阶段聚合。
- OOM:区分堆内存溢出和 Managed Memory 不足,合理配置内存。
- 水位线不推进:检查空闲分区、数据乱序程度和并行度。
10.2 最佳实践
- 优先使用事件时间和 Watermark,保证结果正确性。
- 大状态场景使用 RocksDB 状态后端并开启增量 Checkpoint。
- 合理设置并行度和 Slot 数,避免资源浪费。
- Sink 端优先选择支持事务或幂等的写入方式。
- 上线前做好压测,关注反压和 Checkpoint 稳定性。
- 使用 Flink SQL 降低开发成本,复杂逻辑再下沉到 DataStream。
十一、总结
Flink 的知识体系可以概括为「一个核心、两大抽象、三层保障」:以流为核心,以 DataStream 和 Table/SQL 为两大编程抽象,以状态管理、Checkpoint 容错和端到端一致性为三层保障。掌握这些主干知识后,再结合具体业务场景深入调优,就能在生产环境中稳定发挥 Flink 的实时计算能力。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2401_83857914/article/details/170456908



