订阅更新

两条流要关联——Flink的双流Join怎么做?

Flink手册 第 9 题 约 4 分钟读完

本文目录
  1. 先说结论
  2. Window Join(最安全)
  3. Interval Join(最常用)
  4. Regular Join的状态爆炸问题
  5. 总结

先说结论

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年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器