Apache Doris 4.0.8 CDC 正确性(第 9 篇):Flink Checkpoint 一直成功,表里为什么仍是旧数据

Flink Checkpoint 和 Doris 2PC 都成功,订单 9001 却从已支付退回待支付。没有重复事务,也没有丢失事件;一条更旧的 CDC 记录最后到达,并被精确提交了一次。

2PC 保证批次提交边界,Unique Key 保证一主键一行,只有可靠 Sequence 才能决定乱序事件谁获胜。

四层机制各自只管一件事

层次 负责 不负责
Flink Checkpoint 算子状态与 Source 位点一致恢复 业务事件新旧
Doris Stream Load 2PC Checkpoint 对应事务只提交一次 主键设计和列值正确
Unique Key MoW 相同 Key 只暴露一个逻辑版本 没有 Sequence 时的业务顺序
Sequence 同 Key 按业务版本选胜者 跨 Key 事务约束和漏事件

把这四层都叫 Exactly-Once,事故发生后就只能互相甩锅。

复现一次旧状态回写

错误表只有 Unique Key,没有 Sequence:

sql 复制代码
CREATE TABLE order_state_bad (
    order_id BIGINT,
    op_version BIGINT,
    status VARCHAR(16),
    amount DECIMAL(12,2)
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES ("enable_unique_key_merge_on_write" = "true");

先写版本 105 的已支付,再写迟到的版本 103:

sql 复制代码
INSERT INTO order_state_bad VALUES (9001, 105, 'PAID', 100.00);
INSERT INTO order_state_bad VALUES (9001, 103, 'PENDING', 100.00);

后到行成为可见版本。正确表必须把业务版本映射为 Sequence:

sql 复制代码
CREATE TABLE order_state_good (
    order_id BIGINT,
    op_version BIGINT,
    status VARCHAR(16),
    amount DECIMAL(12,2)
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES (
    "enable_unique_key_merge_on_write" = "true",
    "function_column.sequence_col" = "op_version"
);

同样顺序写入后,版本 105 仍然获胜。

Sequence 选择比字段本身更重要

候选 Sequence 优点 经典失败
应用更新时间 直观 时钟回拨、同秒冲突、不同服务不可比
数据库自增版本 单表稳定 分库后不一定全序
Binlog 文件与 Position 源库提交顺序可靠 需要编码成可比较值,跨源无天然顺序
Kafka Offset 单 Partition 单调 跨 Partition 不可直接比较
业务状态序号 符合领域规则 需要业务明确状态机和补偿语义

不存在脱离 Source 拓扑的万能 Sequence。一个订单的所有事件如果可能分散到多个 Kafka Partition,Offset 就不能直接做全局版本。

DDL 演进会制造另一种旧数据

上游增加字段后,Flink 状态、Connector 映射和 Doris Schema 的生效顺序不一致,可能产生:新字段丢失、默认值覆盖、部分更新失败或整批过滤。

安全顺序应是:

text 复制代码
目标表先兼容新字段
→ Connector 能识别旧与新两种事件
→ 上游开始发送新 Schema
→ 对账新字段非空率与默认值
→ 最后清理旧兼容逻辑

不要用 Checkpoint 成功证明 Schema Evolution 成功。Checkpoint 只保存作业当时接受到的状态。

排障需要两张表

Unique Key 服务表只能看胜者,失败版本可能已被 Delete Bitmap 隐藏。保留一张 Duplicate Key 审计表,记录 Source 位点、事件类型、业务版本和原始载荷:

sql 复制代码
SELECT order_id, op_version, op_type, source_offset, ingest_time
FROM order_event_audit
WHERE order_id = 9001
ORDER BY op_version, ingest_time;

再与服务表比较:

sql 复制代码
SELECT order_id, op_version, status
FROM order_state_good
WHERE order_id = 9001;

审计表回答发生过什么,服务表回答现在是什么。没有审计表时,状态被覆盖后很难证明错误来自源端乱序还是 Sink 合并。

源码证据落在 Delete Bitmap

Doris 4.0.8BaseTablet::calc_segment_delete_bitmap 会查找历史 Rowset 的同 Key 行。历史行 Sequence 更大时,新到行自身进入 Delete Bitmap;新行 Sequence 更大时,历史位置进入 Delete Bitmap。

text 复制代码
Checkpoint 决定这批是否提交
Sequence 决定同 Key 哪行获胜
Delete Bitmap 决定查询跳过哪行
Compaction 最终回收失败版本

这条链解释了为什么不用原地更新也能立即查询唯一状态,也解释了写入侧要承担主键查找和位图维护成本。

修复不能只补一个属性

现有错误表不能靠修改属性安全变成有 Sequence 的正确表。生产修复通常需要新建目标表、从审计事件按最大业务版本重建、双写对账、切换读流量,再停止旧表。

验收至少覆盖 Insert、Update、Delete、同版本冲突、跨 Partition 乱序、Checkpoint 恢复和 DDL 变化。

Flink 可以把每条事件可靠地送到终点,但只有业务版本才能告诉 Doris 哪条事件代表现在。

官方资料与源码

相关推荐
李白客5 小时前
向量数据库怎么选:RAG 项目最该比较的 8 个维度(深度拆解)
数据库·aigc
不会写代码的女程序猿5 小时前
商用 AI 四诊仪技术拆解|明理 AI 四诊仪多模态采集方案解析
大数据·人工智能·科技·ai·健康医疗
cspttty6 小时前
需求预测校招入门:SQL、Excel、统计模型和业务指标怎么学
大数据·数据库
2501_933670796 小时前
面向物流数据分析校招:SQL、Excel、BI、WMS/TMS该怎么准备
数据库
Code_流苏6 小时前
AI 知识库和数据库有什么区别?从“查订单”到“问规则”讲清楚
数据库·ai·agent·知识库
YangYang9YangYan6 小时前
财务 BP 校招面试案例整理|业务场景题 + 数据案例,2027 届求职
大数据·数据库
隔窗听雨眠6 小时前
KingbaseES性能优化实战指南:从操作系统调优到SQL等价改写的完整方法论
数据库·kingbasees
NineData7 小时前
NineData 与统信服务器操作系统完成兼容认证
数据库·oracle·操作系统·软件·数据库管理工具·ninedata·统信
Rosanci15 小时前
谷歌浏览器插件开发实战指南:从 Hello World 到上架发布
大数据·人工智能·chrome·程序人生
m0_4665252916 小时前
云从科技上线云起ModelHub:AI团队时代的模型算力基础设施
大数据·人工智能·科技