2. Flink 基础回顾:Flink 架构、DataStream API、时间语义与 Watermark
在深入实时特征计算之前,必须夯实 Flink 的核心基础。本章将系统回顾 Flink 的运行时架构、DataStream API 编程模型、时间语义以及 Watermark 机制,为后续构建高吞吐、低延迟的因子库与特征服务奠定坚实的理论基础。
2.1 Flink 运行时架构
Flink 采用经典的 主从(Master-Worker)架构,由 JobManager 和 TaskManager 两个核心组件构成,配合 Dispatcher 和 ResourceManager 实现作业的提交、调度与容错。
架构要点:JobManager 负责作业的协调与检查点(Checkpoint)管理;TaskManager 负责执行具体的算子任务(Task),每个 TaskManager 内部包含多个 Task Slot,用于隔离计算资源。
2.2 DataStream API 编程模型
DataStream API 是 Flink 处理无界数据流的核心抽象。一个典型的 Flink 实时作业由 Source、Transformation 和 Sink 三部分组成,形成有向无环图(DAG)。
| 组件 | 作用 | 常见实现 |
|---|---|---|
| Source | 数据接入层,从外部系统读取数据 | KafkaSource、FileSource、SocketSource |
| Transformation | 数据处理逻辑,包括转换、聚合、连接等 | map、flatMap、filter、keyBy、window、process |
| Sink | 结果输出层,将计算结果写入外部存储 | KafkaSink、JDBCSink、FileSink、RedisSink |
特征工程视角:在因子库场景中,Source 通常对接 Kafka 实时事件流;Transformation 层实现因子计算逻辑(如滑动平均、比率计算);Sink 将计算后的特征向量写入在线特征存储(如 Redis 或 HBase)。
以下是一个典型的 DataStream API 作业骨架,展示如何从 Kafka 读取事件、进行窗口聚合、并输出到外部存储:
// 1. 创建执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 2. 配置 Kafka Source
DataStream<String> sourceStream = env
.fromSource(
KafkaSource.<String>builder()
.setBootstrapServers("localhost:9092")
.setTopics("user_click_events")
.setGroupId("flink-feature-group")
.setStartingOffsets(OffsetsInitializer.latest())
.build(),
WatermarkStrategy.noWatermarks(),
"Kafka Source"
);
// 3. 数据转换与特征计算
DataStream<FeatureVector> featureStream = sourceStream
.map(new ParseEventFunction()) // 解析 JSON 事件
.keyBy(event -> event.getUserId()) // 按用户分组
.window(TumblingEventTimeWindows.of(Time.minutes(5))) // 5分钟滚动窗口
.aggregate(new ClickCountAggregate()) // 计算点击次数特征
.name("click_count_feature");
// 4. 输出特征到 Redis Sink
featureStream.sinkTo(
RedisSink.<FeatureVector>builder()
.withHost("redis-cache")
.withPort(6379)
.build()
);
// 5. 提交作业
env.execute("Real-time Feature Computation Job");
2.3 时间语义
Flink 支持三种时间语义,在实时特征计算中,事件时间(Event Time) 是最核心的语义,因为它能准确反映业务事件发生的真实时序,不受数据到达延迟或乱序的影响。
| 时间语义 | 定义 | 特征计算适用场景 |
|---|---|---|
| 事件时间(Event Time) | 事件在业务系统中实际发生的时间戳 | 用户行为序列特征、滑动窗口聚合、跨事件关联 |
| 摄入时间(Ingestion Time) | 事件进入 Flink 系统的时间 | 对时间精度要求不高的统计特征 |
| 处理时间(Processing Time) | 算子所在机器的本地时钟时间 | 实时监控、告警、当前时刻快照特征 |
避坑指南:在特征回溯或离线-实时一致性校验场景中,切勿使用处理时间。处理时间无法保证重复运行结果一致,会导致特征值不可复现,严重影响模型训练与线上推理的一致性。
2.4 Watermark 机制
Watermark 是 Flink 解决事件时间乱序问题的核心机制。它本质上是一个 时间进度信号,表示“当前事件时间已经推进到某个时刻,该时刻之前的数据应该已经全部到达”。
Watermark 的生成策略通常基于事件时间戳与允许的最大乱序延迟:
// 示例:配置 Watermark 策略,允许 10 秒的乱序延迟
WatermarkStrategy<UserEvent> watermarkStrategy = WatermarkStrategy
.<UserEvent>forBoundedOutOfOrderness(Duration.ofSeconds(10))
.withTimestampAssigner((event, timestamp) -> event.getEventTime());
DataStream<UserEvent> streamWithWatermark = sourceStream
.assignTimestampsAndWatermarks(watermarkStrategy);
Watermark 与特征时效性:在实时特征计算中,Watermark 的延迟参数需要在 特征准确性 与 输出时效性 之间做权衡。延迟设置过大,特征更新滞后;设置过小,大量迟到数据导致特征计算不完整。建议根据业务容忍度与数据乱序统计分布动态调整。
2.5 本章小结
本章回顾了 Flink 的三大核心基础:
- 运行时架构:JobManager 与 TaskManager 的主从协作模式,以及 Slot 资源隔离机制。
- DataStream API:Source-Transformation-Sink 三段式编程模型,以及特征工程中的典型应用模式。
- 时间语义与 Watermark:事件时间是特征计算的首选语义;Watermark 是处理乱序数据、保证窗口计算完整性的关键机制。