2. 核心技术选型:实时计算引擎、特征存储与消息队列的对比
做实时特征平台,说白了就是选三样东西:算得快不快、存得对不对、传得稳不稳。这三样分别是实时计算引擎、特征存储和消息队列。我这些年踩过的坑,十有八九都跟选型有关。今天咱们就掰开揉碎了聊聊。
核心观点:没有最好的技术,只有最合适的场景。选型前先问自己三个问题——数据量级多大?延迟要求多高?团队熟悉什么栈?
2.1 实时计算引擎:Flink vs Spark Streaming
实时计算引擎是特征平台的“大脑”。目前主流就两个:Flink 和 Spark Streaming。我个人的习惯是,新项目优先考虑 Flink,但这不是的。
2.1.1 核心差异对比
| 对比维度 | Apache Flink | Spark Streaming |
|---|---|---|
| 计算模型 | 真正的流式计算(逐条处理) | 微批次(Micro-Batch) |
| 延迟 | 毫秒级(< 100ms) | 秒级(通常 1-10s) |
| 状态管理 | 原生强状态(ValueState/MapState) | 依赖外部存储(如 Redis) |
| Exactly-Once 语义 | 原生支持,轻量级 | 支持,但依赖事务写入 |
| SQL 支持 | 成熟,动态表概念 | 较成熟,但微批次语义有局限 |
| 社区活跃度 | 极高,阿里主导 | 高,Databricks 主导 |
为什么会这样?Flink 的设计哲学是“流就是流”,每条数据来了就处理,不攒批。Spark Streaming 则是把流切成一个个小批次,再跑批处理逻辑。你想想看,如果业务要求 200ms 内出特征,Spark Streaming 基本没戏。
我的经验:做风控特征时,延迟要求 500ms 以内,我选了 Flink。做离线特征回刷时,用 Spark 批量处理历史数据,两个引擎配合使用,各取所长。
2.1.2 选型决策树
我一般按这个逻辑来选:
- 延迟要求 < 1s? → 选 Flink,没商量。
- 延迟 1-5s 可接受? → 看团队。熟悉 Java/Scala 选 Flink,熟悉 Python/SQL 选 Spark。
- 需要复杂状态管理? → Flink 原生状态比 Spark 方便太多。
- 批流一体需求? → Flink 1.12+ 已经做得不错,但 Spark 的批处理生态更成熟。
避坑指南:我曾经在一个项目里强行用 Spark Streaming 做毫秒级特征计算,结果调优调了两个月,最后还是切到了 Flink。记住,架构选型上的妥协,最终都会变成技术债。
2.2 特征存储:Redis vs HBase
特征存储是实时特征平台的“肌肉”。特征算出来得存着,而且要能快速读取。我见过不少团队在这上面栽跟头。
2.2.1 核心差异对比
| 对比维度 | Redis | HBase |
|---|---|---|
| 数据模型 | Key-Value,支持多种数据结构 | 宽表,列族存储 |
| 读写延迟 | 微秒级(内存操作) | 毫秒级(依赖 HDFS 和 WAL) |
| 存储容量 | 受内存限制(可加 SSD 缓存) | PB 级,依赖 HDFS |
| 持久化 | RDB/AOF,但非强一致 | 强一致,HDFS 多副本 |
| TTL 过期 | 原生支持,性能极好 | 需自己实现 TTL 机制 |
| 运维复杂度 | 低,主从/集群模式简单 | 高,需要 HDFS/ZK/HBase 全家桶 |
说白了,Redis 适合小数据量、高并发、低延迟的场景。HBase 适合大数据量、稀疏特征、需要强一致的场景。
我的建议:特征存储不要只用一种。我习惯用 Redis 做在线特征缓存(热数据),HBase 做全量特征存储(温冷数据)。这样既保证了读取速度,又解决了容量问题。
2.2.2 实际场景选择
- 用户画像特征(用户数 < 1亿,特征维度 < 1000):Redis Cluster 足够。
- 物品特征(物品数 > 10亿,特征稀疏):HBase 更合适。
- 实时统计特征(如近 5 分钟点击量):Redis 的 Sorted Set 或 Hash 很方便。
- 历史行为序列(需要扫描多行):HBase 的 Scan 操作比 Redis 高效。
小技巧:Redis 的 Pipeline 和 Lua 脚本可以大幅提升批量读写性能。我在做特征拼接时,经常用 Lua 脚本一次读取多个特征,减少网络开销。
2.3 消息队列:Kafka 的核心地位
消息队列是实时特征平台的“血管”。数据从产生到消费,全靠它来传输。说实话,在实时特征这个领域,Kafka 基本是事实标准。
2.3.1 为什么是 Kafka?
| 特性 | Kafka | Pulsar | RocketMQ |
|---|---|---|---|
| 吞吐量 | 极高(百万级 msg/s) | 高(存算分离) | 高(十万级 msg/s) |
| 消息顺序 | 分区内有序 | 分区内有序 | 队列内有序 |
| 消息回溯 | 支持(基于 offset) | 支持(基于 cursor) | 支持(基于时间) |
| 与 Flink 集成 | 原生,Exactly-Once | 较成熟 | 一般 |
| 运维成熟度 | 极高,生态最完善 | 中等 | 中等 |
我个人习惯在实时特征平台里,Kafka 是消息层的首选。原因很简单:Flink 和 Kafka 的集成是最深的,从 checkpoint 到 exactly-once 语义,都是原生支持。
避坑指南:我曾经遇到过一个坑——Kafka 分区数设置不合理。分区太多导致文件句柄耗尽,分区太少导致消费能力不足。我的经验是:分区数 = max(生产者吞吐量 / 分区写入速度, 消费者并行度),一般建议 3 的倍数。
2.4 整体选型框架
这三者不是孤立的,它们需要协同工作。下面这张图展示了实时特征平台的核心技术栈关系:
2.5 选型总结
最后,我整理了一个快速决策表,方便你在实际项目中参考:
| 场景 | 推荐组合 | 理由 |
|---|---|---|
| 高并发低延迟(如推荐系统) | Kafka + Flink + Redis | 毫秒级延迟,高吞吐 |
| 大数据量稀疏特征(如广告系统) | Kafka + Flink + HBase | PB 级存储,列族灵活 |
| 批流一体(如数据中台) | Kafka + Flink + Redis + HBase | 热数据 Redis,冷数据 HBase |
| 团队 Java 技术栈 | Kafka + Flink + Redis | Flink 原生 Java API |
| 团队 Python 技术栈 | Kafka + Spark + Redis | PySpark 生态更成熟 |
最后说一句:选型不是一锤子买卖。我见过太多团队一开始选了“完美”的技术栈,结果业务变了,架构也得跟着变。保持灵活,留好扩展点,比选对技术更重要。