基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 1 章 业务背景与传统 Lambda 架构痛点

基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 ------ 第 1 章 业务背景与传统 Lambda 架构痛点

系列定位 :本系列以车联网 TSP(Telematics Service Provider)行程主题数仓为真实生产案例 ,完整复盘一套 Flink 1.20 + Paimon 1.4 + Doris 4.1 流批一体湖仓的架构设计、建设过程、上线部署、性能优化与踩坑总结。文中所有"踩坑"均为生产环境实测,非理论推演。

版本基线:Flink 1.20.3(JDK 17)+ Paimon 1.4.2(paimon-flink-1.20-1.4.2)+ Doris 4.1.3-rc02 + Flink CDC 3.x + Kafka 3.x + MySQL 8.0 + DolphinScheduler 3.x

与基础教程的关系 :本系列不重复讲组件原理------Paimon 怎么建表、Doris 怎么调优、Flink CDC 怎么配置,请参阅已完结的三套基础教程(《Apache Paimon 1.4.2 从理论到实践》《Apache Doris 4.1 从理论到实践》《Flink CDC 3.5.0 从理论到实践》)。本系列回答的是另一个问题:如何把这些组件拼成一套"实时与离线不打架"的流批一体湖仓,并安全送上生产。


章节导读

  • [1.1 车联网 TSP 平台业务全景](#1.1 车联网 TSP 平台业务全景)
  • [1.2 三大核心需求](#1.2 三大核心需求)
  • [1.3 传统 Lambda 架构的三大痛点](#1.3 传统 Lambda 架构的三大痛点)
  • [1.4 为什么选 Paimon 做湖仓底座](#1.4 为什么选 Paimon 做湖仓底座)
  • [1.5 本章小结与下章预告](#1.5 本章小结与下章预告)

1.1 车联网 TSP 平台业务全景

1.1.1 什么是 TSP 平台

TSP(Telematics Service Provider,车联网服务平台)是连接"车"与"服务"的中间层:车辆上的 TBox 终端把车速、电量、位置、里程等状态数据持续上报到平台,平台在此基础上提供行程查询、能耗分析、围栏告警、车主 App 等服务。

我们案例中的 TSP 平台,每秒产生海量车辆报文(企标数据)。所谓"企标",是企业自定的车载数据上报标准------每条报文是一段 JSON,包含车架号(vin)、采集时间、车速、SOC(电池荷电状态)、经纬度等几十个字段,经 IoT 网关汇入 Kafka。

复制代码
┌──────────┐   MQTT    ┌──────────┐            ┌──────────────────────┐
│ 车辆 TBox │ ────────► │ IoT 网关  │ ─────────► │ Kafka                │
│ (百万级)  │  上报     │ (协议转换) │            │ cnx_vehicle_data_qb  │
└──────────┘           └──────────┘            │ (企标报文 topic)      │
                                               └──────────┬───────────┘
                                                          │
                    ┌──────────────────┐                  │
                    │ MySQL 业务库      │                  ▼
                    │ 车型/组织/用户维表 │            (数据入湖,见第 4 章)
                    └──────────────────┘

1.1.2 数据的三个特点

在动手设计之前,先认清这份数据的"脾气"------后面所有架构决策都源于这三个特点:

特点 具体表现 对架构的影响
报文级高频 每秒全量车辆持续上报,单日原始报文量以亿计 ODS 层必须高吞吐写入,且写入要幂等(重放不翻倍)
字段频繁增补 企标报文字段随车型迭代、业务需求不断新增 ODS 层不能做 schema 展开,必须存原文,否则每加一个字段就要改链路
维表在 MySQL 车型、组织、用户等维表由业务系统维护在 MySQL,频繁变更 维表需 CDC 实时同步入湖,且要同时服务实时与离线两条链路

1.1.3 本案例的范围界定:行程主题数仓

车联网平台要建的主题有很多(告警、充电、驾驶行为......),本系列聚焦其中一个完整落地的主题------行程主题数仓:

复制代码
┌────────────────────────────────────────────────────────────────┐
│                  行程主题数仓的范围                              │
└────────────────────────────────────────────────────────────────┘

  输入:企标报文(vin / collect_time / json_data 原文)
        + MySQL 维表(车型 / 组织 / 用户)

  核心加工:把"一条条报文"加工成"一段段行程"
    · SESSION 窗口切分:连续报文聚合成一次出行
    · 行程内编号与分段:报文序号 rn、行程分段
    · 行程级汇总:单次行程的里程、能耗、时长、起止点
    · 日 / 月聚合与全历史快照:每人每天的行程数、累计能耗......

  输出:
    · 实时看板(当天行程、当日能耗/里程累计)
    · T+1 权威报表(任意历史区间回算)
    · 车主 App 行程详情查询

选择行程主题作为案例,是因为它同时踩中了流批一体的所有难点:既要秒级出当天数据(实时),又要 T+1 权威口径(离线),还有全历史递推指标(日累计、滚动平均 SOH)这个"流式最难啃的骨头"。行程主题打通了,其他主题就是复制粘贴。


1.2 三大核心需求

业务方最初给的需求只有三句话,但每句话背后都是硬指标:

# 需求 具体指标 难点
① 实时看板 车辆当天行程、当日能耗/里程累计,秒级~分钟级可见 数据量大、时效要求高
② 离线报表 T+1 的历史权威统计 ,支持任意历史区间回算与口径修正 权威性、可重算性
③ 统一口径 实时与离线最终数据一致 ,且互不踩踏 一致性、写冲突隔离

1.2.1 需求①:实时看板------"秒级~分钟级"

运营大屏要展示"今日全平台行程数""当日总能耗",车主 App 要看"我今天开了多远"。这两个场景的时效底线不同:

  • 运营大屏:分钟级可接受;
  • 车主 App 当天行程:秒级体验才合格。

注意措辞是"秒级~分钟级 "------这意味着当天数据不要求严格秒级一致,允许一个短暂的校准窗口。这个细节在第 10 章"实时先行、离线校准"设计中被充分利用,是整套方案能落地的关键妥协点。

1.2.2 需求②:离线报表------"权威"与"可回算"

财务对账、运营月报、政府上报用的数据,必须以 T+1 离线口径为权威值 。更重要的是"任意历史区间回算与口径修正":

  • 业务口径变了(比如"行程"的定义从 30 分钟隔断改为 20 分钟)→ 历史数据要能按新口径重算;
  • 上游补传了某天的报文 → 那一天的数据要能重跑。

这就要求:ODS 原始数据必须长期在手,且下游全链路可幂等重算。"ODS 在,一切可以重算"是本系列反复出现的设计哲学。

1.2.3 需求③:统一口径------重点是"互不踩踏"

"实时与离线最终一致"好理解:车主上午 10 点看到的当日里程,与第二天报表里的昨日里程,误差必须收敛到可接受范围。

但真正决定方案成败的是后半句------"互不踩踏":

实时链路写它的表、离线链路写它的表,谁也不能覆盖、污染、干扰对方的输出。哪怕两边跑在同一张物理表的不同分区上,也必须保证"每个分区只有一个写入者"。

这条需求在传统 Lambda 架构里靠"物理隔离"天然满足(两套存储嘛),但也正是物理隔离带来了口径对不齐的死结(下一节详述)。我们最终方案的核心,就是找到一种办法:让两条链路共享存储(口径天然可对齐),同时通过契约设计做到互不踩踏。


1.3 传统 Lambda 架构的三大痛点

1.3.1 改造前的架构

平台原有的数仓是典型 Lambda 架构:实时链路与离线链路各自独立,各存一份数据、各写一套逻辑。

复制代码
┌────────────────────────────────────────────────────────────────────┐
│                  改造前:传统 Lambda 架构                           │
└────────────────────────────────────────────────────────────────────┘

                        ┌──────────┐
                        │   Kafka   │ 企标报文
                        └─────┬────┘
              ┌───────────────┴───────────────┐
              ▼                               ▼
   ┌─────────────────────┐        ┌─────────────────────────┐
   │ 实时链路              │        │ 离线链路                  │
   │                      │        │                          │
   │  Flink 作业          │        │  Sqoop 导数 + Spark ETL  │
   │       ▼              │        │       ▼                  │
   │  Kafka 中间结果       │        │  Hive ODS / DWD / DWS   │
   │       ▼              │        │       ▼                  │
   │  Redis / MySQL       │        │  Impala 查询             │
   │  (当天指标)           │        │  (T+1 报表)              │
   └──────────┬──────────┘        └────────────┬────────────┘
              │                                │
              ▼                                ▼
        ┌─────────────────────────────────────────┐
        │  应用层:自己判断"什么时候读实时、什么时候读离线" │
        └─────────────────────────────────────────┘

1.3.2 痛点一:两套存储,链路长且异构

实时侧是 Kafka + Redis(当天指标缓存),离线侧是 Hive + Impala(T+1 报表)。两套存储意味着:

  • 数据物理上存了两份,一份在 Kafka/Redis,一份在 Hive;
  • 中间还要 Sqoop、Spark 等多个搬运环节,每一环都是故障点;
  • 想查"某车某天的完整行程明细"?实时侧 Redis 只存聚合值,离线侧 Hive 要等 T+1------当天明细两头都查不到。

1.3.3 痛点二:两套逻辑,口径对不齐

这是最致命的痛点。同一条"行程数"指标,实时链路用 Flink 代码算,离线链路用 Spark SQL 算------两套引擎、两套代码、两个团队维护,口径必然漂移。

一个真实场景:运营发现大屏上"今日行程数 1023",而第二天 T+1 报表显示"昨日行程数 1018",差 5 条。排查结果:实时链路的 SESSION 窗口超时配的是 25 分钟,离线链路是 30 分钟------两套代码里同一个业务概念的参数悄悄分叉了。更糟的是,这种分叉不会报错,只会让数字慢慢偏。

1.3.4 痛点三:运维成本高

环节 问题
Sqoop 全量导数 每日全量跑,源库压力大;增量方案又依赖脆弱的时间戳字段
Hive 小文件 高频写入导致小文件爆炸,Impala 查询越来越慢
回算困难 口径修正要重跑历史?Sqoop 重导 + Spark 全量重算,一个主题动辄半天
两套告警 实时 Flink 作业与离线 Spark 作业的监控、告警、重启各自一套
人员割裂 实时逻辑一个团队、离线逻辑一个团队,改口径要两边协同发版

1.3.5 小结:Lambda 的本质矛盾

把三个痛点归拢一下,Lambda 架构的根本矛盾是:

为了"实时与离线互不干扰",付出了"数据存两份、逻辑写两套"的代价;而逻辑写两套,就永远无法保证口径一致。

有没有办法只存一份数据、各写各的表(物理上仍隔离),但共享同一套存储与元数据?这就是我们转向流批一体湖仓的动机。


1.4 为什么选 Paimon 做湖仓底座

1.4.1 目标架构

复制代码
┌────────────────────────────────────────────────────────────────────┐
│              改造后:流批一体湖仓(本系列目标架构)                   │
└────────────────────────────────────────────────────────────────────┘

                Kafka(cnx_vehicle_data_qb 企标报文)
                          │  Flink 消费(实时入湖)
                          ▼
   tsp_ods.ods_vehicle_qb_msg_report_original   ←------  两链路唯一共享点
   (Paimon,按天分区,vin 分桶)                        MySQL 维表
            │                                        │ Flink CDC(yaml pipeline)
            ├────────────────────┐                   ▼
   [离线] DS 调度批作业            │            Paimon 维表(ods 层)
   runtime-mode=BATCH             │
   R1:只写 dt <= T-1             │        [实时] 常驻流作业(9 个作业链)
   INSERT OVERWRITE 幂等          │        R2:只写 dt >= T(屏障)
   dwd → dws → ads(原名)         │        dwd_*_rt → dws_*_rt → ads_*_rt
            │                     │        _cum_rt 的 T-1 种子行由离线独家写
            ▼                     ▼
   ┌──────────────────────────────────────────────┐
   │              Doris 服务层                      │
   │  · Paimon Catalog 直查(当天/明细)             │
   │  · 异步物化视图 MV(历史聚合加速,离线表之上)    │
   │  · VIEW v_*(R3:历史走 MV,当天走实时直查)     │
   └──────────────────────────────────────────────┘
                       ▼
                 BI / APP / 对账

核心变化一句话:用 Paimon 这一个湖存储,同时承载实时与离线两条链路的输出;查询层用 Doris 统一收口。

1.4.2 为什么是"同一存储、同一 Catalog"

选 Paimon 做底座,最关键的不是它的性能参数,而是这两个"同一":

  1. 同一存储 :实时表(_rt 后缀)与离线表(原名)都是 Paimon 表,物理上分表隔离(互不踩踏),逻辑上同源同根(口径可对齐)。实时与离线的差异只剩"写了哪张表、哪个分区",而不是"两套完全异构的系统"。
  2. 同一 Catalog :两条链路共用同一个 Hive Metastore Catalog。实时作业通过 LOOKUP JOIN 读维表,离线批作业直接批读同一批维表------一份维表、一处维护、两处使用。

1.4.3 流批各写各的表,查询层统一收口

在同一个湖上,两条链路各写各的表:

  • 离线链路:DolphinScheduler 调度批式 FlinkSQL,INSERT OVERWRITE 整区覆盖,只写 dt <= T-1(铁律 R1);
  • 实时链路:9 个常驻流作业分层递进,只写 dt >= T(铁律 R2);
  • 唯一交汇点:递推累计表 _cum_rt 的 T-1 种子行,由离线种子作业独家写入------分区级单写者,零冲突。

对外查询不直接暴露湖表,而是收口到 Doris 服务层:历史数据走异步物化视图加速,当天数据走 Paimon Catalog 直查,再用一个分流 VIEW(铁律 R3)把"历史走离线、当天走实时"对 BI 屏蔽掉------BI 只换一个表名,SQL 零改动。

三条铁律(R1/R2/R3)是整套方案的基石,第 2 章展开。

1.4.4 与"两套存储各自同步"方案的本质区别

有人会问:"保持 Lambda 两套存储,每天凌晨用同步工具把离线结果灌进实时侧,不也能对齐吗?"

这正是第 12 章要专门拆解的"伪需求"。先说本质区别:

对比项 两套存储 + 同步工具 同一湖存储(本方案)
数据份数 两份,靠同步保持"近似一致" 一份,实时/离线各写各的表
一致性 同步延迟窗口内不一致,且同步失败会静默漂移 同源数据,最终天然一致
口径修正 要改实时 + 离线 + 同步三处逻辑 改离线 SQL 重算即可,实时次日被种子校准
当天明细 实时侧通常只存聚合值,明细查不到 湖里有全量明细(_rt 表),随时可查
故障半径 同步链路挂了,两边数据开始分叉 实时链路整体停掉,历史查询完全不受影响

一句话:"同步"是让两份不一致的数据变得看起来一致;"湖仓一体"是让数据从源头就只有一份。

1.4.5 为什么是 Paimon + Doris 这个组合

选型 关键理由
Paimon 做湖底座 原生支持主键表与 upsert(实时链路必需);与 Flink 集成最紧密(FlinkSQL 直接读写);支持 Hive Metastore Catalog(与存量 Hive 数仓无缝共存);changelog 机制支撑下游流读
Flink 1.20 做流批引擎 同一套 FlinkSQL 语法,runtime-mode 切换流批,离线批作业直接批读 Paimon;与已运行的 Flink 实时作业共用运维体系
Doris 做服务层 BI/App 的"筛选 + 聚合 + 高并发点查"是交互式负载,Paimon 的 scan 式查询扛不住;Doris 通过 Multi-Catalog 直查 Paimon,异步物化视图把历史聚合压到毫秒级
Flink CDC 同步维表 MySQL 维表整库入湖,schema.change.behavior=evolve 应对维表频繁变更
DolphinScheduler 做调度 离线作业链的依赖编排、失败重跑、SQL 指纹防呆(第 15 章详述)

版本组合警告 :这套组合"能用",但版本兼容是踩坑重灾区 ------Paimon connector 必须严格匹配 Flink 版本(paimon-flink-1.20-1.4.2),Doris 4.1 的 Arrow 读取与 Flink 类型映射有暗坑(DATEV2 被读成带时区 TIMESTAMP)等。本系列第 17 章会逐一拆解 14 类实测问题,选型前请务必先读那一章。


1.5 本章小结与下章预告

本章小结

复制代码
┌────────────────────────────────────────────────────────────────┐
│                     第 1 章 要点回顾                            │
└────────────────────────────────────────────────────────────────┘

  ✓ 业务全景:TSP 平台每秒海量企标报文,行程主题数仓为落地案例
  ✓ 数据三特点:报文级高频 / 字段频繁增补 / 维表在 MySQL
  ✓ 三大需求:实时看板(秒级~分钟级)/ 离线报表(权威可回算)
              / 统一口径(最终一致 + 互不踩踏)
  ✓ Lambda 三痛点:两套存储 / 两套逻辑口径对不齐 / 运维成本高
  ✓ 根本矛盾:为"互不干扰"付出"存两份、写两套"的代价,
              而逻辑写两套就永远无法保证口径一致
  ✓ 破局思路:同一 Paimon 存储 + 同一 Catalog,流批各写各表,
              Doris 统一收口;三条铁律保证互不踩踏

关键结论(供后文反复引用)

结论 后文落点
ODS 是全仓唯一真相源,必须存报文原文 第 4 章 ODS 表设计
"秒级~分钟级"时效容忍 1 天校准窗口 第 10 章 实时先行、离线校准
"互不踩踏"= 每个分区只有一个写入者 第 2/12 章 分区契约铁律
实时链路停掉不影响对外查询 第 13 章 Doris 服务层切流回滚

下章预告

第 2 章 流批一体湖仓总体架构与三条分区契约铁律 :把本章的目标架构图逐层拆开,讲清 R1(离线只写 dt <= T-1)、R2(实时只写 dt >= T)、R3(查询历史走离线、当天走实时)三条铁律的落地方式,以及唯一交汇点"种子作业"的设计。三条铁律违反任何一条,实时与离线的数据就会打架------它们是后面 16 章一切内容的基石。

官方参考资料

相关推荐
QYR_111 小时前
硝基乙烷市场规模持续扩张:2032年全球销售额预计达1.96亿美元,行业前景稳步向好
大数据·人工智能
HUIBUR科技1 小时前
多系统整合不必搭建中台:AI中枢带来轻量化数字化集成
大数据·运维·人工智能
Codiggerworld1 小时前
寒露·Codigger
大数据·程序员·节日
GlobalInfo1 小时前
2026年AIoT芯片及平台市场报告正式发布:市场规模、十五五趋势与产业链全景一键获取
大数据·人工智能·ai·半导体
小羊没烦恼!2 小时前
Windows Azure Platform体验(1):Windows Azure
java·大数据·后端·python·flask·word·.net
计算机毕业设计杰瑞2 小时前
【2027大数据精品毕设】基于大数据的高频电力消耗数据可视化与分析,附源码_数据可视化_数据分析_毕设选题_开题ppt_大数据项目_文档指导
大数据·信息可视化·课程设计
俊哥大数据2 小时前
基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 2 章 流批一体湖仓总体架构与三条分区契约铁律
flink·doris·湖仓一体·paimon
俊哥大数据2 小时前
基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 4 章 Kafka 企标报文入湖(ODS 表设计)
flink·doris·湖仓一体·paimon·流批一体
weishuangyun12 小时前
小程序制作平台怎么选?三大平台对比!
大数据·开发语言·javascript