实时计算技术选型:流处理 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,但恢复时间只有几十秒。
Kafka消息队列基础:实时计算的「血管」
没有Kafka,Flink就是个光杆司令。Kafka负责把数据从各个系统「喂」给Flink。
Kafka的核心概念其实不多:
- Topic:数据分类,比如「股票行情」「订单流」「成交回报」
- Partition:Topic的分片,每个Partition内部有序
- Consumer Group:一组消费者,共同消费一个Topic
- Offset:消息在Partition中的位置,类似书签
为什么Kafka这么快?因为它把数据顺序写到磁盘,利用操作系统的PageCache,读的时候直接从内存命中。说白了,就是「顺序写+零拷贝」。
Kafka在风控中的典型用法
我参与的一个实时风控项目,数据流是这样的:
- 交易所行情 -> Kafka Topic: market-data (100个Partition)
- Flink消费market-data,计算实时敞口
- 计算结果写入Kafka Topic: risk-results
- 下游告警系统消费risk-results,触发风控动作
这里有个坑:Partition数量要和Flink的并行度匹配。如果Flink设了10个并行度,但Kafka只有1个Partition,那9个并行度就闲着。我曾经犯过这个错,后来改成Partition数=并行度×2,才把吞吐量拉满。
知识体系总览
下面这张图,是我自己总结的实时计算技术选型框架。你可以把它当作本章的「思维导图」:
这张图把今天讲的内容串起来了。你可以看到,流处理、批处理、消息队列三者是并列关系,但实际项目中往往是组合使用。Flink和Kafka是黄金搭档,Spark则更适合离线场景。
好了,这一章就到这里。记住一句话:没有最好的技术,只有最合适的方案。下一章我们会深入Flink的Time与Window机制,那是实时风控的核心中的核心。