两条流要关联——Flink的双流Join怎么做?
先说结论
Flink的双流Join分三种:
Window Join: 两条流在同一个时间窗口内Join。状态只保留窗口范围,不会爆炸。
Interval Join: 两条流在一个时间范围内Join(如“订单时间前后5分钟的点击”)。状态只保留区间范围。
Regular Join(无界 Join): 两条流不限时间Join。状态会无限增长,必须配合State TTL使用!
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
双流Join是Flink最复杂也最实用的功能之一。比如实时把订单流和用户信息流关联、把点击流和广告展示流关联。但双流Join的坑很多:状态爆炸、结果不准确、延迟高。今天把Flink所有的Join方式和适用场景讲清楚。
Window Join(最安全)
-- Flink SQL的Window Join
SELECT o.order_id, o.amount, u.user_name
FROM orders o, users u
WHERE o.user_id = u.user_id
AND o.order_time BETWEEN u.update_time - INTERVAL '10' MINUTE
AND u.update_time + INTERVAL '10' MINUTE;
窗口关闭后状态自动清理,不用担心状态爆炸。但缺点是只能Join同一时间窗口内的数据。
Interval Join(最常用)
// DataStream API的Interval Join
orderStream
.keyBy(o -> o.getUserId())
.intervalJoin(clickStream.keyBy(c -> c.getUserId()))
.between(Time.minutes(-5), Time.minutes(5)) // 订单时间前后5分钟
.process(new ProcessJoinFunction<Order, Click, Result>() {
@Override
public void processElement(Order o, Click c, Context ctx, Collector<Result> out) {
out.collect(new Result(o.getOrderId(), c.getClickId(), o.getAmount()));
}
});
Interval Join的状态只保留between范围内的数据,可控。我在当前短剧出海公司做广告归因时,用Interval Join把“广告点击流”和“应用安装流”在点击后24小时内关联,做归因分析。
Regular Join的状态爆炸问题
如果你用Flink SQL写了一个普通的JOIN(没有时间条件):
-- ✖ 危险:Regular Join,状态会无限增长!
SELECT o.order_id, u.user_name
FROM orders o JOIN users u ON o.user_id = u.user_id;
-- ✔ 安全:配合State TTL
-- 在Flink配置里设置:
-- table.exec.state.ttl = 86400000 -- 24小时后自动清理
我在元宇宙社交App早期写过一个Regular Join而没设置TTL,结果跑了3天后状态超过50GB,Checkpoint超时失败,作业崩溃。从那以后我的规矩:所有Regular Join必须配置State TTL。
总结
| Join类型 | 状态管理 | 适用场景 |
|---|---|---|
| Window Join | 窗口关闭自动清理 | 两流时间对齐的场景 |
| Interval Join | 只保留区间范围数据 | 最常用,两流有时间关联 |
| Regular Join | 无限增长,必须TTL | 无时间限制的关联 |
面试时能说清楚三种Join的区别和状态管理方式,再加一个“Regular Join状态爆炸50GB”的踩坑,就很有深度。
下一篇聊一个实时数仓的经典难题:实时指标和离线对不上——实时数仓的数据一致性怎么保证?
你们生产环境用哪种Join最多?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长