深蓝黑背景品牌封面:居中大标题两行「让数据在数据库、NoSQL 与大数据平台之间实时流动」,副标题「CDC + 消息队列的实时数据管道」;下方装饰——左侧数据库圆柱经一条流动虚线箭头穿过中间的消息队列方块,分流到右侧的 NoSQL 闪电图标与数据湖波浪图标;顶部标注「历史题目复盘 · 系统设计」与「Day 09 · 09-27」 图 1:本文封面,点明「CDC + 消息队列」的管道主线。

先说明属性:这是一篇历史题目复盘,题目出自本地历史面试资料(见文末来源说明),与任何公司的当前招聘无关。这是一道开放式系统设计题:业务数据产生在数据库里,线上查询要用 NoSQL,离线分析和训练要用大数据平台,如何让数据在三者之间实时流动?

先给核心结论:主流答案是一条「数据库变更日志 → CDC 捕获 → 消息队列 → 多路消费写入」的管道。架构图好画,这道题的分水岭在四个关键问题上:顺序、重复、一致性、结构演进。答得出架构只能算及格,答得出这四个问题才算懂数据管道。

第一步,先破题:为什么不能直接双写。

最朴素的方案是应用代码同时写数据库、NoSQL 和数仓。它死在两个地方:一是任何一次部分失败都会留下不一致的三份数据,补偿逻辑越写越复杂;二是每接一个下游就要改一次业务代码。让数据「流动」的正确姿势,是让数据库自己把变更说出来,而不是让业务代码挨个通知。

第二步,主干架构:CDC 加消息队列。

数据库的每一次增删改都会写入自己的变更日志(比如 binlog),CDC(变更数据捕获)组件订阅这份日志,把行级变更翻译成一条条事件,写入消息队列;队列下游挂多路消费者,一路写入 NoSQL 支撑在线低延迟查询,一路写入数仓或数据湖支撑离线分析。Apache Kafka 的官方文档把这种事件流平台概括为三种能力:发布订阅事件流、持久化存储、实时或回溯处理,并且按 key 分区保证同一 key 的事件落在同一分区、按写入顺序读取——这个特性正是下文「顺序」问题的答案。

这条管道的三个好处要说出来:业务代码零侵入,下游增减只需增删消费者;队列削峰,下游抖动不拖垮上游;事件可重放,下游数据损坏能从队列重新消费恢复。

第三步,四个关键问题逐个拆。

顺序:同一主键的「插入后更新」如果乱序到达,下游就是错的。解法是按主键分区投递,让同一行的变更永远走同一分区、由同一消费者按序处理。

重复:队列的常态是至少一次投递,消费者宕机重启后同一条事件可能再来一遍。消费端必须幂等——按主键覆盖写、或记录已处理的事件版本号,重复事件落下去结果不变。

一致性:跨三个存储系统没有分布式事务可用,只能接受最终一致。要交代的是兜底手段:监控消费延迟与积压量,超过阈值报警;定期全量对账,发现不一致按数据库为准修复。

结构演进:上游表加了一列,旧格式消息和新格式消息会在队列里共存。消息要带 schema 版本,消费者能同时解析新旧格式,升级期间不做停服切换。

这四个问题有一个共同点:它们都不是选型问题,而是语义问题。换任何一款消息队列、任何一个 CDC 工具,顺序、重复、一致性、结构演进都原样站在那里,所以答题时讲清取舍比报工具名字重要得多。

架构图:业务数据库的每一次增删改产生 binlog,CDC 组件订阅 binlog 把变更变成事件流,写入消息队列(削峰、解耦、可重放),两路消费者分别把数据写入 NoSQL 支撑在线低延迟查询、写入数仓或数据湖支撑离线分析与训练。右侧四个关键问题:①顺序——同一主键的变更必须按序到达,按主键分区投递;②重复——队列至少一次投递,消费端必须幂等;③一致性——接受最终一致,用延迟与积压监控兜底;④结构演进——表结构变更时新旧消息要能共存解析。底部结论:这条管道就是训练数据管道与特征平台的通用骨架 图 2:跨存储实时数据流的架构,与顺序、重复、一致性、结构演进四个关键问题。

易错点清单。

一,用应用双写当主方案,讲不出部分失败时的不一致怎么收场。二,画得出架构图,被问「同一行连续更新乱序了怎么办」就卡住——没提按主键分区。三,假设队列恰好一次投递,消费端不做幂等。四,承诺强一致,不知道跨异构存储只能最终一致加监控兜底。五,没考虑过表结构变更时新旧消息共存的解析问题。

回到面试现场,建议的答题节奏:先否掉双写并说明理由,再画「CDC → 队列 → 多路消费」的主干,然后主动把顺序、重复、一致性、结构演进四张牌打出来,最后补一句监控与对账的兜底。训练数据管道、特征平台、实时样本回流,用的就是这套骨架——AI 数据基础设施的核心不是模型,而是这条管道。

如果面试官追问「下游数仓要求每小时做一次全量快照对齐,这条实时管道还需要吗」,你会怎么权衡实时与批量的边界?欢迎写出你的方案。

参考资料

  • Apache Kafka 官方文档(事件流平台的三种能力:发布订阅、持久化存储、实时或回溯处理;topic 按 key 分区,同一 key 的事件写入同一分区并按写入顺序读取;Kafka Connect 用于从关系型数据库等外部系统持续导入导出数据) — https://kafka.apache.org/documentation/