1. 订单已经支付,看板为什么还没变化
业务数据库里,订单 order-1042 已经从待支付改成已支付。运营看板上的成交金额却没有变化。
这个问题不能只检查 Dashboard SQL。一笔订单到达看板,要经过完整链路:
订单服务
→ MySQL Binlog / Order Event
→ Kafka
→ Flink
→ StarRocks 明细表
→ 聚合表或物化视图
→ BI Dashboard每一段都有自己的进度和失败方式。业务库更新成功,只能证明交易系统接受了这次修改;它无法证明 Kafka 已经收到事件、Flink 已经处理、StarRocks 已经提交,或者看板查询使用了正确指标。
2. 一笔订单会产生多次变化
订单并非创建后就保持不变。一个简化过程可能是:
CREATED → PAID → SHIPPED → FINISHED
└→ REFUNDING → REFUNDED如果把每次变化直接追加到分析表,下面的查询会把同一订单计算多次:
SELECT SUM(amount)
FROM order_event
WHERE status = 'PAID';分析平台需要明确保存“事件历史”还是“订单当前状态”。两者都可能需要,但用途不同:
| 数据 | 适合回答的问题 |
|---|---|
| 订单事件明细 | 状态何时变化,处理路径是什么 |
| 订单当前快照 | 当前有多少已支付订单 |
| 指标聚合 | 某时间范围的成交、退款和转化 |
事件至少需要稳定身份:
event_id
order_id
user_id
shop_id
status
amount
event_time
order_versionevent_id 用来识别一次业务事件,order_id 标识业务对象,order_version 帮助判断同一订单变化的先后关系。只依赖消息到达时间,无法处理网络重试和迟到事件。
3. Kafka 保存的是有序分区中的记录
Kafka Topic 被分成多个 Partition。生产者通常用 order_id 作为 Key,让同一订单的事件进入同一分区,从而保持该分区内的顺序。
这不代表所有订单拥有全局顺序,也不代表消费者业务天然不会重复。消费者失败恢复、生产者重试和下游事务边界都会影响最终结果。
Java 订单服务还要解决“数据库已提交,但事件没有发出”的间隙。常见方案会把业务变更和待发送事件放在同一个本地事务中,再由独立发布器把事件送入 Kafka。本文只讨论这条边界,不把某一种 CDC 或 Outbox 实现写成唯一选择。
业务事务
├─ UPDATE orders
└─ INSERT event_outbox
发布器
→ 读取未发送事件
→ 写入 Kafka
→ 记录发布结果即使发布器重试,稳定的 event_id 也让下游有机会识别同一事件。
4. Flink Checkpoint 保护的是处理状态
Flink 可以保存算子状态和数据源进度。发生故障后,作业从 Checkpoint 恢复,重新读取尚未完成的一段数据。
状态可能包括:
每个订单已看到的最大版本
窗口中的金额聚合
去重所需的 event_id
Kafka 消费位置Checkpoint 成功不等于下游结果一定只写一次。端到端语义还依赖 Source、状态后端、Sink 和外部系统是否共同支持相应协议。
StarRocks Flink Connector 的 exactly-once 支持有明确的版本与配置条件。文章写作时需要记录所核对的 Connector、Flink 和 StarRocks 版本,不能只在架构图旁标一个“Exactly Once”。
5. StarRocks 主键表承接订单当前状态
订单当前快照可以使用主键模型表达。下面只保留说明字段:
CREATE TABLE order_current (
order_id BIGINT NOT NULL,
user_id BIGINT,
shop_id BIGINT,
status VARCHAR(32),
amount DECIMAL(18, 2),
event_time DATETIME,
order_version BIGINT
)
PRIMARY KEY (order_id)
DISTRIBUTED BY HASH(order_id);上面的 DDL 是说明示例。分桶、排序键、分区、数据副本和更新顺序需要结合数据规模与官方版本配置。
主键表让同一 order_id 的新状态覆盖旧状态。它解决的是表内更新模型,不能自动判断一个版本更旧的迟到事件是否应该覆盖新状态。处理链路仍要携带并校验业务版本。
StarRocks 的 Routine Load 可以持续消费 Kafka 数据,Flink Connector 则适合已经在 Flink 中完成清洗、关联和状态处理的链路。选择入口时要看转换复杂度、状态需求和统一运维方式。
6. 三个“成功”需要分别记录
一次事件进入实时 BI,可以拆成:
采集成功:事件进入 Kafka
处理成功:Flink 完成当前 Checkpoint 覆盖的计算
写入成功:StarRocks 提交对应批次看板仍可能因为查询缓存、物化视图刷新、权限或指标条件而显示旧结果。因此还要记录:
- Kafka 最新位置与消费积压。
- Flink 最近成功 Checkpoint 和失败原因。
- StarRocks 导入任务状态、异常行与数据时间。
- 指标表最近更新时间与看板查询时间。
把所有延迟合并成一个“接口慢”,很难定位问题发生在哪一段。
7. Java 后端在这条链路里的位置
Java 业务服务负责产生带有稳定标识和业务版本的订单变化。数据平台控制面可以继续管理 Topic、作业、数据表、指标任务和告警记录,但不会替代 Kafka Broker、Flink Runtime 或 StarRocks 查询引擎。
一个可追踪事件需要把业务身份贯穿下去:
order_id + event_id
→ Kafka record key / headers
→ Flink record
→ StarRocks detail row
→ BI drill-down看板发现异常金额时,才能沿着标识回到订单和原始事件。
沿着订单变化拆下去会发现,“实时数仓”并不只是把消息写进一个查询很快的数据库。实时链路实际包含业务事件、消息顺序、状态恢复、写入事务和指标查询等多个环节,每个环节都有可观察的状态,链路才能被追踪和恢复。