恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 1 章 业务背景与传统 Lambda 架构痛点
首页
资讯中心
/
基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 1 章 业务背景与传统 Lambda 架构痛点
基于 FlinkSQL + Paimon + Doris 的车联网流批一体湖仓实践 —— 第 1 章 业务背景与传统 Lambda 架构痛点
发布时间:2026/10/13 10:11:19
基于 FlinkSQL Paimon Doris 的车联网流批一体湖仓实践 —— 第 1 章 业务背景与传统 Lambda 架构痛点系列定位本系列以车联网 TSPTelematics Service Provider行程主题数仓为真实生产案例完整复盘一套Flink 1.20 Paimon 1.4 Doris 4.1流批一体湖仓的架构设计、建设过程、上线部署、性能优化与踩坑总结。文中所有踩坑均为生产环境实测非理论推演。版本基线Flink 1.20.3JDK 17 Paimon 1.4.2paimon-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.2 三大核心需求1.3 传统 Lambda 架构的三大痛点1.4 为什么选 Paimon 做湖仓底座1.5 本章小结与下章预告1.1 车联网 TSP 平台业务全景1.1.1 什么是 TSP 平台TSPTelematics 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、行程分段 · 行程级汇总单次行程的里程、能耗、时长、起止点 · 日 / 月聚合与全历史快照每人每天的行程数、累计能耗…… 输出 · 实时看板当天行程、当日能耗/里程累计 · T1 权威报表任意历史区间回算 · 车主 App 行程详情查询选择行程主题作为案例是因为它同时踩中了流批一体的所有难点既要秒级出当天数据实时又要 T1 权威口径离线还有全历史递推指标日累计、滚动平均 SOH这个流式最难啃的骨头。行程主题打通了其他主题就是复制粘贴。1.2 三大核心需求业务方最初给的需求只有三句话但每句话背后都是硬指标#需求具体指标难点①实时看板车辆当天行程、当日能耗/里程累计秒级~分钟级可见数据量大、时效要求高②离线报表T1 的历史权威统计支持任意历史区间回算与口径修正权威性、可重算性③统一口径实时与离线最终数据一致且互不踩踏一致性、写冲突隔离1.2.1 需求①实时看板——“秒级~分钟级”运营大屏要展示今日全平台行程数“当日总能耗”车主 App 要看我今天开了多远。这两个场景的时效底线不同运营大屏分钟级可接受车主 App 当天行程秒级体验才合格。注意措辞是秒级~分钟级——这意味着当天数据不要求严格秒级一致允许一个短暂的校准窗口。这个细节在第 10 章实时先行、离线校准设计中被充分利用是整套方案能落地的关键妥协点。1.2.2 需求②离线报表——“权威与可回算”财务对账、运营月报、政府上报用的数据必须以 T1 离线口径为权威值。更重要的是任意历史区间回算与口径修正业务口径变了比如行程的定义从 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 查询 │ │ (当天指标) │ │ (T1 报表) │ └──────────┬──────────┘ └────────────┬────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────┐ │ 应用层自己判断什么时候读实时、什么时候读离线 │ └─────────────────────────────────────────┘1.3.2 痛点一两套存储链路长且异构实时侧是 Kafka Redis当天指标缓存离线侧是 Hive ImpalaT1 报表。两套存储意味着数据物理上存了两份一份在 Kafka/Redis一份在 Hive中间还要 Sqoop、Spark 等多个搬运环节每一环都是故障点想查某车某天的完整行程明细实时侧 Redis 只存聚合值离线侧 Hive 要等 T1——当天明细两头都查不到。1.3.3 痛点二两套逻辑口径对不齐这是最致命的痛点。同一条行程数指标实时链路用 Flink 代码算离线链路用 Spark SQL 算——两套引擎、两套代码、两个团队维护口径必然漂移。一个真实场景运营发现大屏上今日行程数 1023而第二天 T1 报表显示昨日行程数 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 目标架构┌────────────────────────────────────────────────────────────────────┐ │ 改造后流批一体湖仓本系列目标架构 │ └────────────────────────────────────────────────────────────────────┘ Kafkacnx_vehicle_data_qb 企标报文 │ Flink 消费实时入湖 ▼ tsp_ods.ods_vehicle_qb_msg_report_original ←—— 两链路唯一共享点 Paimon按天分区vin 分桶 MySQL 维表 │ │ Flink CDCyaml pipeline ├────────────────────┐ ▼ [离线] DS 调度批作业 │ Paimon 维表ods 层 runtime-modeBATCH │ 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 做底座最关键的不是它的性能参数而是这两个同一同一存储实时表_rt后缀与离线表原名都是 Paimon 表物理上分表隔离互不踩踏逻辑上同源同根口径可对齐。实时与离线的差异只剩写了哪张表、哪个分区而不是两套完全异构的系统。同一 Catalog两条链路共用同一个 Hive Metastore Catalog。实时作业通过 LOOKUP JOIN 读维表离线批作业直接批读同一批维表——一份维表、一处维护、两处使用。1.4.3 流批各写各的表查询层统一收口在同一个湖上两条链路各写各的表离线链路DolphinScheduler 调度批式 FlinkSQLINSERT 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.behaviorevolve应对维表频繁变更DolphinScheduler 做调度离线作业链的依赖编排、失败重跑、SQL 指纹防呆第 15 章详述版本组合警告这套组合能用但版本兼容是踩坑重灾区——Paimon connector 必须严格匹配 Flink 版本paimon-flink-1.20-1.4.2Doris 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 章一切内容的基石。官方参考资料Apache Paimon 官网https://paimon.apache.org/docs/1.4.2/Apache Doris 官网https://doris.apache.org/zh-CN/docs/4.x/Apache Flink 1.20 文档https://nightlies.apache.org/flink/flink-docs-release-1.20/Flink CDC 文档https://nightlies.apache.org/flink/flink-cdc-docs/release-3.5/Apache DolphinScheduler 官网https://dolphinscheduler.apache.org/zh-cn本系列配套基础教程《Apache Paimon 1.4.2 从理论到实践》《Apache Doris 4.1 从理论到实践》《Flink CDC 3.5.0 从理论到实践》