Flink CDC + Iceberg 实时入湖:MySQL Binlog 到湖仓表完整链路

长文技术整理分类:湖仓架构阅读 5310评论 392026-04-24
参考 Flink CDC、Dynamic Iceberg Sink 和实时湖仓资料,整理从 MySQL CDC 到 Iceberg 表的链路设计。

实时入湖不是简单同步表

MySQL 到 Iceberg 的实时入湖链路,核心不是“能同步”,而是更新、删除、DDL、Exactly-once、小文件和查询一致性。日志表 append 相对简单,订单、库存、用户这类业务表必须处理主键更新和删除。

MySQL Binlog -> Flink CDC -> 清洗补字段 -> Iceberg v2 -> Trino/Spark/Doris 查询
                 |              |
                 |              +-- schema evolution / compaction
                 +-- checkpoint / savepoint / restart

MySQL 侧要先检查

Iceberg 表设计

Iceberg v2 支持 row-level delete,更适合 CDC 更新删除场景。分区不要过细,低流量表按小时分区会制造大量小文件。高频查询按 dt、业务域、状态过滤,就要把这些字段纳入分区或排序设计。

CREATE TABLE lake.ods_order (
  id BIGINT,
  user_id BIGINT,
  status STRING,
  amount DECIMAL(18,2),
  op_ts TIMESTAMP(3),
  dt STRING,
  PRIMARY KEY (id) NOT ENFORCED
) PARTITIONED BY (dt)
WITH (
  'format-version'='2',
  'write.upsert.enabled'='true'
);

DDL 和 Schema 演进

真实业务一定会新增字段、修改字段长度、枚举值扩展。建议把源库 DDL、Flink SQL、Iceberg schema、下游查询四件事放到同一个发布流程里。否则源表字段已经有了,湖仓表还是旧结构,下游查到大量 null。

小文件和快照治理

Checkpoint 间隔越短、并行度越高、分区越细,小文件越多。Iceberg 的 metadata、manifest、snapshot 也会增长,影响查询 planning。

CALL catalog.system.rewrite_data_files('lake.ods_order');
CALL catalog.system.rewrite_manifests('lake.ods_order');
CALL catalog.system.expire_snapshots('lake.ods_order', TIMESTAMP '2026-04-01 00:00:00');

对账怎么做

入湖后不要只看任务 RUNNING。至少要对账:主键数、金额汇总、删除记录数、最大更新时间、分区行数。CDC 链路的正确性问题往往不是立刻报错,而是悄悄多数据或少数据。

生产环境可以直接套用的总结

如果把这篇内容落到真实项目里,建议至少补齐三类信息:第一是基线数据,包括日均数据量、峰值 QPS、任务耗时、存储大小和失败频率;第二是关键配置,包括并行度、分区数、TTL、超时时间、批大小、索引字段;第三是验证结果,包括上线前后耗时对比、资源消耗对比、核心指标对账和异常回滚记录。

写技术博客时也可以按这个顺序组织:先讲业务背景,再讲为什么原方案不稳,然后贴出关键配置或 SQL,最后用对比数据说明优化是否有效。这样文章不会空,也不会像模板填空。

延伸阅读和落地建议

本文按公开技术资料和生产经验重新整理,没有复制原文。真正落地到你的环境时,建议补充:集群版本、资源规格、任务截图、SQL 执行计划、核心监控曲线、上线前后对比数据。这样文章会更像真实生产复盘,也更适合长期维护。