金融级实时流处理系统
金融级实时流处理系统(Flink)。整个项目围绕股票交易数据的“接入 -> 清洗路由 -> 窗口聚合排序 -> 多路输出”构建,兼顾了高吞吐、低延迟与数据准确性。
结合你提供的所有代码片段,我为你梳理了整个项目的框架、各模块作用及相互调用关系:
🏗️ 整体架构分层
整个项目可以划分为四个核心层次:数据源层 (Source)、业务处理层 (Process & Window)、数据模型层 (Model & Parser)、数据输出层 (Sink)。
📂 1. 数据源层 (com.example.flink.source)
负责从外部系统(本地文件或 Redis)拉取原始的股票行情数据,并将其转化为 Flink 内部的 StockEvent 对象。
CsvTailSource:文件监听器。像 Linux 的tail -f一样,实时监控本地 CSV 文件的增量内容。它支持断点续传(记录读取偏移量)、自动跳过表头,并将读取到的每一行原始文本转换为StockEvent下发。RedisSubscribeSource:静态 Redis 订阅器。连接 Redis Pub/Sub,根据配置好的频道列表(如stock_000001)阻塞监听实时消息,解析后下发。TidbSecurityChannelProvider:动态频道提供者。配合动态订阅源使用,负责定期通过 JDBC 查询 TiDB 数据库,获取当前有效的股票代码白名单,并按分片规则生成对应的 Redis 频道列表。- (注:你在对话中提到的
DynamicRedisSubscribeSource会持有TidbSecurityChannelProvider,实现频道的动态热更新)。
⚙️ 2. 业务处理层 (com.example.flink.process & window)
这是系统的“大脑”,负责对原始数据进行清洗、分流和按时间窗口聚合。
BoundaryRoutingProcessFunction:智能路由算子。作为前置过滤器,它判断数据是否在合法的交易时段内(支持事件时间与处理时间的双重校验)。合法的数据走主路,非交易时段或脏数据被打入侧输出流(Side Output)进行隔离。SecurityWindowSortFunction:窗口排序算子。继承自ProcessWindowFunction。当滚动时间窗口触发时,它会将同一支股票(Keyed by securityId)在窗口内的所有乱序数据,严格按照交易所序列号(ApplSeqNum)进行升序重排,确保下游拿到的是绝对有序的数据。EventTimeWithProcessingFallbackTrigger:高可靠触发器。为窗口提供“双保险”触发机制。正常情况下等待水印(Watermark)推进来触发;如果水印停滞(如午间休盘),则通过处理时间定时器强制兜底触发,防止窗口数据长期不输出。
📦 3. 数据模型层 (com.example.flink.model & parser)
贯穿整个链路的基础设施,定义了数据的结构和转换规则。
StockEvent:核心数据载体(POJO)。封装了股票交易的各个字段(如证券代码、序列号、成交时间、原始行文本等),在各个算子之间传递。StockEventParser:数据解析工具类。负责将 Source 层读取到的原始字符串(CSV行或 JSON)解析并实例化为StockEvent对象,包含基础的数据清洗逻辑(如去除 BOM 头、格式校验)。
💾 4. 数据输出层 (com.example.flink.sink)
负责将处理好的结果数据分发到不同的下游系统,满足监控、存储和实时推送的需求。
CsvAppendSink:本地文件落盘。将排序后的数据以追加模式写入本地 CSV 文件。内置了批量刷新(Batch Flush)和定时刷新机制,极大提升了磁盘 I/O 性能。RedisPubSubSink:实时消息广播。将处理好的数据重新打包,通过 Redis Pipeline 批量发布到指定的 Redis 频道,供前端页面或其他微服务实时消费。ApplSeqNumAlertSink:异常告警哨兵。旁路挂载在主流程上,专门监测序列号是否超过阈值。利用原子类(AtomicBoolean)保证在海量数据中只打印一次告警日志,防止日志风暴。
🔗 核心调用与数据流转关系
整个 Flink 作业的主链路调用关系如下:
-
数据接入:
CsvTailSource/RedisSubscribeSource启动,拉取外部数据。- 调用
StockEventParser.parse()将原始文本转为StockEvent。 - 通过
SourceContext.collect()将数据注入 Flink 管道。
-
清洗与分流:
- 数据流入
BoundaryRoutingProcessFunction。 - 正常数据通过
out.collect()进入主路;异常数据通过ctx.output(boundaryOutputTag)进入旁路。
- 数据流入
-
分组与窗口计算:
- 主路数据经过
keyBy(securityId)按键分组。 - 进入带有
EventTimeWithProcessingFallbackTrigger的时间窗口。 - 窗口触发时,调用
SecurityWindowSortFunction.process(),对窗口内的Iterable<StockEvent>进行内存排序。
- 主路数据经过
-
多路分发:
- 排序后的数据被依次输出,并行流向三个 Sink:
- 调用
CsvAppendSink.invoke()-> 写入本地磁盘。 - 调用
RedisPubSubSink.invoke()-> 推送至 Redis 消息队列。 - 调用
ApplSeqNumAlertSink.invoke()-> 执行阈值监控告警。
- 调用
- 排序后的数据被依次输出,并行流向三个 Sink:
这个框架设计得非常严谨,既利用了 Flink 的状态管理和窗口机制保证了金融数据的有序性与一致性,又通过自定义的 Source/Sink 和触发器解决了实际生产中的可靠性与性能瓶颈。

浙公网安备 33010602011771号