2. Flink 基础回顾:架构、API、时间语义与 Watermark
在进入实时特征计算与因子库结合之前,必须夯实 Flink 核心基础。本章聚焦 Flink 运行时架构、DataStream API 编程模型、Event Time / Processing Time 两种时间语义,以及 Watermark 机制——这是构建低延迟、高准确率实时特征 pipeline 的基石。
2.1 Flink 运行时架构
Flink 采用 主从(Master-Worker) 架构,核心组件包括 JobManager、TaskManager 和 Client。作业提交后,Client 将 JobGraph 发送给 JobManager,JobManager 负责调度、检查点协调与故障恢复;TaskManager 是实际执行任务的 Worker,每个 TaskManager 包含多个 Task Slot,Slot 是资源调度的最小单位。
2.2 DataStream API 核心概念
DataStream API 是 Flink 实时处理的主要编程接口。核心抽象包括 Source(数据源)、Transformation(转换算子)和 Sink(输出端)。在因子库场景中,Source 通常对接 Kafka,Transformation 实现特征计算逻辑,Sink 写入 Redis / HBase / ClickHouse。
| 类别 | 常用算子 | 因子库典型用途 |
|---|---|---|
| Source | KafkaSource, FileSource, SocketSource | 从 Kafka topic 读取行情、订单流 |
| Transformation | map, flatMap, filter, keyBy, window, process | 因子计算、数据清洗、分组聚合 |
| Sink | KafkaSink, RedisSink, JDBCSink | 因子结果写入在线存储或消息队列 |
keyBy 通常按股票代码或因子 ID 分区,确保同一标的的事件进入同一个算子实例,保证状态一致性。
2.3 时间语义:Event Time vs Processing Time
Flink 支持三种时间语义,其中 Event Time 和 Processing Time 是实时特征计算中最常用的两种。选择哪种时间语义直接决定因子计算的准确性与延迟。
- Processing Time:算子所在机器的系统时钟。延迟最低,但结果依赖数据到达顺序,不可复现。适用于对精度要求不高的实时监控指标。
- Event Time:事件实际发生的时间戳(通常嵌入在数据中)。结果可复现,能正确处理乱序数据,但需要配合 Watermark 机制。因子库中绝大多数特征(如过去 5 分钟均价、累计成交量)必须使用 Event Time。
2.4 Watermark 机制
Watermark 是 Flink 中衡量 Event Time 进度的核心机制,本质是一个 单调递增的时间戳,表示“当前时间之前的数据已经全部到达”。当 Watermark 超过窗口结束时间时,触发窗口计算并输出结果。
2.4.1 Watermark 生成策略
Flink 提供两种内置 Watermark 生成器:
- 周期性生成(Periodic):每隔一定时间(如 100ms)生成一次 Watermark,适用于大部分实时场景。
- 断点式生成(Punctuated):每条数据到达时判断是否生成 Watermark,适用于数据稀疏或特殊标记场景。
// 周期性 Watermark 生成示例(允许 5 秒乱序)
DataStream<Event> stream = env
.fromSource(source, WatermarkStrategy
.<Event>forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((event, timestamp) -> event.getEventTime()),
"Kafka Source");
2.4.2 Watermark 与窗口的交互
| 窗口类型 | 触发条件 | 因子库场景 |
|---|---|---|
| Tumbling Window | Watermark >= 窗口结束时间 | 整点统计因子(如每分钟累计成交额) |
| Sliding Window | Watermark >= 每个滑动窗口结束时间 | 滚动特征(如过去 5 分钟、10 分钟均价) |
| Session Window | Watermark >= 会话间隔 + 最后事件时间 | 用户行为间隔因子 |