实时计算技术选型:流处理 vs 批处理、Apache Flink核心概念、Kafka消息队列基础

各位同学,欢迎来到第二章。上一章我们聊了金融风险计算的业务场景和整体架构,今天咱们要落地了——选技术。

说实话,选型这件事,我踩过的坑比你们想象的多。早年做风控系统,我一股脑上了纯批处理,结果行情剧烈波动时,风险指标滞后了整整5分钟。那一次,客户差点把桌子掀了。所以,今天的内容,我会把当年那些血泪教训揉碎了讲给你们听。

流处理 vs 批处理:不是非黑即白

很多人问我:实时计算是不是一定要用流处理?批处理是不是就淘汰了?

我的回答是:看场景。

批处理,说白了就是「攒一批,算一次」。比如每天收盘后算一次VaR,用Spark或者Hive跑个几十分钟,完全没问题。但如果你要监控盘中实时敞口,批处理就抓瞎了——等你算出来,行情都变了三波了。

流处理呢?来一条数据算一次,延迟在毫秒级。Apache Flink、Kafka Streams、Spark Streaming都属于这个阵营。我个人的习惯是:凡是涉及「止损监控」「实时保证金」「盘中风险限额」的,一律上流处理

核心判断标准: 你的业务能容忍多少延迟?秒级以内选流处理,分钟级以上可以批处理。

但别急着站队。我在项目中遇到过一种混合架构:白天用Flink做实时风控,晚上用Spark做批量回测和报表。两者数据源一致,只是计算窗口不同。说白了,工具是死的,业务是活的。

Apache Flink核心概念:从「有状态」说起

Flink为什么在金融圈这么火?因为它天生就是为「有状态计算」设计的。

你想想看,计算一个投资组合的实时VaR,你需要知道过去N天的历史数据,还要知道当前持仓。这些「历史信息」就是状态。Flink把状态管理得明明白白,不像Spark Streaming那样需要依赖外部存储。

1. DataStream API:你的第一行Flink代码

先看个最简单的例子——实时计算股票价格的平均值:

// 伪代码,但逻辑是完整的
DataStream<StockPrice> stream = env
    .addSource(new KafkaSource<>("stock-prices"))
    .keyBy(stock -> stock.getSymbol())
    .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
    .aggregate(new AveragePrice());

stream.print();

这段代码干了什么?

  • Source:从Kafka读数据
  • KeyBy:按股票代码分组
  • Window:开一个5秒的滚动窗口
  • Aggregate:算平均值

嗯,这里要注意:窗口大小决定了你的计算粒度。5秒窗口适合高频交易,但如果是日终风控,窗口可能是1小时甚至1天。

2. 状态后端:你的「记忆体」

Flink的状态后端有三种:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。

类型 存储位置 适用场景
MemoryStateBackend JVM堆内存 小状态、调试用
FsStateBackend 文件系统(HDFS/S3) 中等状态、需要容错
RocksDBStateBackend 本地磁盘+RocksDB 超大状态(TB级)

我曾经在项目中遇到状态爆炸——一个投资组合的持仓数据有几十GB,用MemoryStateBackend直接OOM了。后来换成RocksDBStateBackend,问题解决。所以,金融场景下,我建议直接上RocksDB,别犹豫。

3. Checkpoint与Savepoint:容错的艺术

实时系统最怕什么?挂掉。Flink的Checkpoint机制就是用来做故障恢复的。

简单说,Flink会定期把当前状态和偏移量保存下来。一旦挂了,重启后从最近的Checkpoint恢复,数据一条不丢。我见过最夸张的场景:一个Flink作业跑了3个月,Checkpoint文件占了几个TB,但恢复时间只有几十秒。

我的经验: Checkpoint间隔别设太短,否则频繁写盘会影响性能。一般设30秒到1分钟比较合理。

Kafka消息队列基础:实时计算的「血管」

没有Kafka,Flink就是个光杆司令。Kafka负责把数据从各个系统「喂」给Flink。

Kafka的核心概念其实不多:

  • Topic:数据分类,比如「股票行情」「订单流」「成交回报」
  • Partition:Topic的分片,每个Partition内部有序
  • Consumer Group:一组消费者,共同消费一个Topic
  • Offset:消息在Partition中的位置,类似书签

为什么Kafka这么快?因为它把数据顺序写到磁盘,利用操作系统的PageCache,读的时候直接从内存命中。说白了,就是「顺序写+零拷贝」。

Kafka在风控中的典型用法

我参与的一个实时风控项目,数据流是这样的:

  1. 交易所行情 -> Kafka Topic: market-data (100个Partition)
  2. Flink消费market-data,计算实时敞口
  3. 计算结果写入Kafka Topic: risk-results
  4. 下游告警系统消费risk-results,触发风控动作

这里有个坑:Partition数量要和Flink的并行度匹配。如果Flink设了10个并行度,但Kafka只有1个Partition,那9个并行度就闲着。我曾经犯过这个错,后来改成Partition数=并行度×2,才把吞吐量拉满。

避坑指南: 我曾经在生产环境遇到过Kafka消息积压,原因是Consumer处理太慢。后来加了监控,一旦Lag超过阈值就报警。记住:没有监控的Kafka,就是定时炸弹

知识体系总览

下面这张图,是我自己总结的实时计算技术选型框架。你可以把它当作本章的「思维导图」:

实时风险计算引擎 流处理 批处理 消息队列 Apache Flink Kafka Streams Spark Streaming Apache Spark Hive/MapReduce Presto/Trino Apache Kafka RabbitMQ Pulsar DataStream API 状态后端 Checkpoint Topic/Partition Consumer Group Offset 图:实时计算技术选型知识体系

这张图把今天讲的内容串起来了。你可以看到,流处理、批处理、消息队列三者是并列关系,但实际项目中往往是组合使用。Flink和Kafka是黄金搭档,Spark则更适合离线场景。

好了,这一章就到这里。记住一句话:没有最好的技术,只有最合适的方案。下一章我们会深入Flink的Time与Window机制,那是实时风控的核心中的核心。


专注资料整理