维表JOIN:实时流怎么关联维度数据
同步查询 · 异步IO · 缓存策略 · Lookup Join · 广播维表
📋 面试题
Flink实时任务怎么关联维度表?有哪几种方案?各有什么优缺点?
为什么维表JOIN是难题?
离线数仓JOIN两张Hive表很简单。但实时场景下:主流是无限的,维度表在外部数据库(MySQL/Redis),每条数据都要去查一次外部系统,性能是大问题。
四种方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 同步查询 | 每条数据同步查DB | 简单直接 | 太慢,容易反压 |
| 异步IO | 异步查DB不阻塞 | 吞吐高 | 实现复杂些 |
| 缓存+异步 | 查完缓存,未命中查DB | 性能好 | 缓存一致性 |
| Flink SQL Lookup Join | SQL语法直接关联 | 最简单 | 底层也是查DB |
| 广播维表 | 维表广播到所有算子内存 | 最快,无IO | 维表不能太大 |
方案一:Flink SQL Lookup Join(推荐)
-- 维度表声明
CREATE TABLE dim_user (
user_id STRING,
user_name STRING,
city STRING,
PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://host:3306/db',
'table-name' = 'dim_user',
'lookup.cache.max-rows' = '10000', -- 缓存1万行
'lookup.cache.ttl' = '1h' -- 缓存1小时
);
-- Lookup Join
SELECT o.order_id, o.amount, u.user_name, u.city
FROM orders AS o
JOIN dim_user FOR SYSTEM_TIME AS OF o.proc_time AS u
ON o.user_id = u.user_id;
FOR SYSTEM_TIME AS OF是Flink SQL的临时表关联语法,表示用处理时间去查维度表的当前值。
方案二:广播维表(小维表首选)
// 维度表小(<100MB),直接广播到所有并行度
MapStateDescriptor<String, UserInfo> descriptor =
new MapStateDescriptor<>("dim_user", String.class, UserInfo.class);
BroadcastStream<UserInfo> broadcastDim =
dimStream.broadcast(descriptor);
mainStream.connect(broadcastDim)
.process(new BroadcastProcessFunction<Order, UserInfo, EnrichedOrder>() {
@Override
public void processElement(Order order, ReadOnlyContext ctx, Collector<EnrichedOrder> out) {
UserInfo user = ctx.getBroadcastState(descriptor).get(order.getUserId());
out.collect(new EnrichedOrder(order, user));
}
@Override
public void processBroadcastElement(UserInfo user, Context ctx, Collector<EnrichedOrder> out) {
ctx.getBroadcastState(descriptor).put(user.getUserId(), user);
}
});
我们广告归因里用广播维表关联广告计划信息。广告计划表只有几万条,加载到内存几十MB。查询零延迟,比查MySQL快1000倍。
缓存策略选择
| 维表大小 | 更新频率 | 推荐方案 |
|---|---|---|
| <100MB | 低频 | 广播维表 |
| 100MB-1GB | 中频 | Lookup Join + 缓存 |
| >1GB | 高频 | 异步IO + Redis缓存 |
📌 总结
| 记忆点 | 内容 |
|---|---|
| 难点 | 实时流每条数据都要查外部系统 |
| SQL方案 | Lookup Join + 缓存TTL(最简单) |
| 小维表 | 广播维表,查询零延迟 |
| 大维表 | 异步IO + Redis缓存 |
| 选型依据 | 维表大小 × 更新频率 |
▶ 下一篇预告:DAY 13 实时数仓架构
Wood聊大数据 | 9年大数据老兵,聊技术、聊职场、聊成长
小红书正文
实时流怎么关联维度表?这是Flink面试的高频实战题。
难点:流是无限的,维度表在MySQL/Redis里,每条数据都要查一次外部系统。
四种方案:① 同步查DB——简单但太慢 ② 异步IO——吞吐高但实现复杂 ③ Flink SQL Lookup Join——最简单,加缓存TTL就行 ④ 广播维表——小维表首选,查询零延迟。
选型依据:维表<100MB用广播,100MB-1GB用Lookup Join+缓存,>1GB用异步IO+Redis。
我们广告计划信息用广播维表,几万条加载到内存。比查MySQL快1000倍。