一、引言
Flink计算引擎已成为大数据实时计算领域的事实标准,然而还是有不少应用场景不适合使用Flink进行实时加工与关联计算,本文简单聊聊一些不适用场景。
二、大窗口 / 无界多对多 JOIN
典型场景:两张事实表做 Regular Join,双方都持续产生大量数据,且无法限定时间范围。
vbnet
-- 这种 JOIN 在 Flink 中状态会无限膨胀
SELECT *
FROM orders o
JOIN payments p ON o.order_id = p.order_id
问题本质: Flink 必须把两侧所有未匹配的数据存在 State 里,如果业务上关联窗口不可控(比如下单到支付间隔可能是几秒也可能是几个月),State 会持续增长直到 OOM 或 checkpoint 超时。
State TTL 能解决吗? 能缓解,但设短了丢数据,设长了状态照样膨胀。本质是拿准确性换资源。
三、全量快照关联(非增量语义)
典型场景: 每次计算需要基于全量数据重新关联,而非只处理增量变化。
- 每天凌晨取全量用户画像 JOIN 全量订单,生成宽表
- 需要对历史全量数据做 "截面" 关联(某个时间点的全量快照)
为什么不适合 Flink: Flink 流式 JOIN 是增量驱动的,每来一条数据触发一次关联。全量快照语义需要的是"等两边数据都到齐再算",这天然是批的语义。
四、复杂多表级联 JOIN(5 张表以上)
典型场景: A JOIN B JOIN C JOIN D JOIN E,级联很深。
实际问题:
- 每个 JOIN 算子都要维护独立 State,5 个 JOIN 就是 10 份 State(每个 JOIN 左右各一份)
- State 总量 = 表数据量 × JOIN 层数,资源需求指数级增长
- 任何一张表的数据延迟都会导致中间结果产生回撤(Retract),下游抖动严重
- Checkpoint 变大变慢,恢复时间不可控
经验阈值: 3 张表以内的流式 JOIN 比较可控,超过 5 张且数据量大时,Spark 微批通常更稳定。
五、需要全局排序 / 全局聚合后再关联
典型场景:
sql
-- 先算全局排名,再用排名结果做关联
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY score DESC) as rk
FROM user_scores
)
SELECT r.*, u.name
FROM ranked r JOIN users u ON r.user_id = u.user_id
WHERE r.rk <= 1000
问题:全局排序需要单并行度处理所有数据,无法分布式并行。Flink 能做,但吞吐受限,大数据量下远不如 Spark 的 Sort-Merge 高效。
六、非等值关联 / 复杂谓词关联
典型场景:
sql
SELECT *
FROM events e
JOIN rules r ON e.amount BETWEEN r.min_amount AND r.max_amount
AND e.category LIKE r.pattern
问题:Flink 的流式 JOIN 优化依赖等值条件做 Hash 分区。非等值条件意味着无法按 key 分区,要么退化为笛卡尔积(Nested Loop),要么需要广播小表。数据量一大就不现实。
七、迟到数据需要精确修正历史结果
典型场景: 数据可能延迟数小时甚至数天到达,到达后需要精确修正所有受影响的关联结果。
Flink 的处理方式: 通过 Retract 流回撤旧结果、发送新结果。但如果下游是 HBase 这种 KV 存储还好(幂等覆盖),如果下游需要"知道历史版本"或涉及聚合指标修正,Retract 链路会非常复杂。
Spark 微批更合适: 每个批次基于当前全量数据重算,天然保证最终一致性,不需要管 Retract 语义。
八、关联逻辑频繁变更 + 需要回刷历史
业务特点: 关联规则每周都在改,每次改完需要回刷过去 N 天的数据。
Flink 的困境: 流作业改逻辑意味着重启,State 不兼容就要丢弃从头消费,回刷成本高。
Spark 更适合: 改 SQL 跑一遍历史数据就行,天然支持幂等重跑。
九、计算引擎选型决策
sql
关联场景评估:
│
├─ 能否限定关联时间窗口?
│ ├─ 能(< 小时级)→ Flink Interval Join ✓
│ └─ 不能 / 窗口跨天 → 倾向 Spark
│
├─ JOIN 表数量?
│ ├─ ≤ 3 张 → Flink 可控 ✓
│ └─ > 5 张且数据量大 → 倾向 Spark
│
├─ 是否等值 JOIN?
│ ├─ 是 → Flink 高效 ✓
│ └─ 非等值 / 范围关联 → 倾向 Spark
│
├─ 是否需要全量快照语义?
│ ├─ 否,增量即可 → Flink ✓
│ └─ 是 → Spark
│
└─ 数据延迟容忍度?
├─ 秒级 → 必须 Flink
├─ 分钟级 → Flink 或 Spark Structured Streaming
└─ 十分钟以上可接受 → Spark 微批更稳
Flink 流式 JOIN 的核心约束是 State 大小和关联边界的可控性。一旦关联窗口不可控、表数量多、或需要全量重算语义,Spark 微批反而是更稳定、更经济的选择。两者不是替代关系,而是互补。