订阅更新

维表JOIN:实时流怎么关联维度数据

Flink 实时计算 20 天 · 第 12 讲 进阶 约 4 分钟读完

同步查询 · 异步IO · 缓存策略 · Lookup Join · 广播维表

本文目录
  1. 📋 面试题
  2. 为什么维表JOIN是难题?
  3. 四种方案对比
  4. 缓存策略选择
  5. 📌 总结

📋 面试题

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倍。

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