Flink简介:基于行的流处理模型 | AI生成和翻译
问题:介绍Apache Flink,并阐明其数据模型是行式还是列式。
答案:
Flink 是什么
Apache Flink 是一个分布式流处理引擎。其核心抽象是一个无界的事件流,以低延迟逐条处理记录。批处理被视为流的一种特殊情况(有界流),两者在同一运行时下统一——这就是“一切都是流”的理念,使其区别于 Spark 的“一切都是批(微批)”起源。
核心支柱:
- 有状态流处理 — 算子持有状态(例如,运行中的聚合、窗口、连接),并通过检查点持久化到可靠存储以实现精确一次语义。
- 事件时间 + 水位线 — 通过判断事件发生的时间与到达的时间来处理乱序事件。
- 分层 API — DataStream API(底层、命令式),Table API / SQL(声明式、关系型)。
行式还是列式?
Flink 的运行时从根本上说是行式的。流模型在数据流经算子 DAG 时逐条处理记录(一行)。这对于流处理来说是自然的选择:当事件持续到达并且你需要毫秒级延迟时,你无法等待累积一列的值。
具体来说:
- DataStream API → 每个元素是一个记录/对象。行式导向。
- Table API / SQL → 逻辑抽象是表,但物理执行仍然流式传输
RowData对象(Flink 的内部行表示,org.apache.flink.table.data.RowData)。每个RowData是一个逻辑行,带有类型化字段访问器。 - 状态后端(RocksDB、堆)→ 键值存储,其中值是序列化的行。
你之前指出的细微差别是正确的:Flink 的连接器读取和写入列式格式。当 Flink 读取 Parquet 或 ORC 文件时,它会进行向量化列式读取以提高源端效率,然后转换为行式 RowData 进行处理。因此,列式出现在 I/O 边界,而不是流处理核心。
有一个值得注意的例外:Flink 在某些路径中添加了具有列式/向量化执行的批处理算子(并与 Apache Arrow 集成用于 PyFlink UDF,其中 Arrow 的列式内存格式避免了跨 JVM↔Python 边界的每行序列化开销)。但默认的流处理引擎仍然是逐行处理。
这对你的思维模型为何重要
| 引擎 | 原生模型 | 优化方向 |
|---|---|---|
| Flink | 行式,流 | 低延迟、有状态事件处理(类似 OLTP 的流) |
| Spark | 微批,逐渐列式化(Tungsten + Arrow) | 吞吐量,批分析 |
| DuckDB / ClickHouse | 列式,向量化 | OLAP 扫描/聚合 |
当你在事件到达时处理完整事件并需要全记录状态时,行式是正确的默认选择。当你在海量静态数据集上扫描少量列时,列式更胜一筹。Flink 属于前者;它仅在边缘(文件 I/O、跨语言 UDF)借用列式技巧,因为这些场景下向量化能带来收益而不损害流模型。
如果你在银行接触到 Flink(这在金融事件/交易管道中很常见),实际要点是:在你的处理逻辑中思考 RowData,并让连接器在源/汇处处理列式与行式之间的转换。