金融级实时流处理系统

金融级实时流处理系统(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 作业的主链路调用关系如下:

  1. 数据接入

    • CsvTailSource / RedisSubscribeSource 启动,拉取外部数据。
    • 调用 StockEventParser.parse() 将原始文本转为 StockEvent
    • 通过 SourceContext.collect() 将数据注入 Flink 管道。
  2. 清洗与分流

    • 数据流入 BoundaryRoutingProcessFunction
    • 正常数据通过 out.collect() 进入主路;异常数据通过 ctx.output(boundaryOutputTag) 进入旁路。
  3. 分组与窗口计算

    • 主路数据经过 keyBy(securityId) 按键分组。
    • 进入带有 EventTimeWithProcessingFallbackTrigger 的时间窗口。
    • 窗口触发时,调用 SecurityWindowSortFunction.process(),对窗口内的 Iterable<StockEvent> 进行内存排序。
  4. 多路分发

    • 排序后的数据被依次输出,并行流向三个 Sink:
      • 调用 CsvAppendSink.invoke() -> 写入本地磁盘。
      • 调用 RedisPubSubSink.invoke() -> 推送至 Redis 消息队列。
      • 调用 ApplSeqNumAlertSink.invoke() -> 执行阈值监控告警。

这个框架设计得非常严谨,既利用了 Flink 的状态管理和窗口机制保证了金融数据的有序性与一致性,又通过自定义的 Source/Sink 和触发器解决了实际生产中的可靠性与性能瓶颈

posted @ 2026-05-19 20:55  左耳听风  阅读(16)  评论(0)    收藏  举报