去年我接手了一个订单中心的数据同步需求:MySQL 里接近亿级的订单数据要同步到 ES,支撑后台的实时筛选和搜索。最初我对方案的预期很简单——定时跑个 batch 把数据导过去就完事,直到业务方明确要求下单后十几秒内必须能在管理后台搜到订单,我才意识到这事儿的复杂度比表面看起来高得多。最终我选择了 FlinkCDC 这条链路:MySQL Binlog → FlinkCDC → Elasticsearch。这篇博文会把整个实战过程完整记录下来,包括环境版本怎么选、Binlog 怎么开、任务怎么写、上线后踩了哪些坑,以及后期运维需要盯住的几个关键指标,给准备做类似数据同步的朋友一个可以直接参考的完整链条。
1. 先聊选型:为什么最终是 FlinkCDC 而不是 DataX 或 Canal
1.1 我实际对比过的三种同步方案
接到这个需求时,团队内部对“工具选型”其实讨论过好几轮。大家最熟悉的自然是 DataX,调研了一圈之后发现它并不适合这个场景。DataX 是典型的离线批量同步工具,适合固定时间窗口的全量导出,比如凌晨 2 点把昨天的订单导出到数仓。但我们的业务要求是秒级延迟——订单状态一旦变更,后台搜索必须立刻能看到。DataX 的定时调度的最短粒度通常也是分钟级,而且每次跑全量对源库压力也不小,所以直接排除。
另一个常见选项是 Canal 监听 Binlog,然后自己写一个消费端转发到 ES。Canal 本身很成熟,但它本质上只解决了“怎么拿到 Binlog 变更”这一层,后续的解析、过滤、幂等写入、状态管理全部要自己实现。我们团队当时人力紧张,不想再维护一套自研消费框架。而且 Canal 在高并发写入场景下,自己管理位点、做重启恢复的成本不低,一个不小心就会造成数据丢失或重复。
FlinkCDC 的优势在于它把整条链路串起来了:FlinkCDC 负责读取 Binlog 变更事件,Flink 作为计算引擎负责处理数据转换,ES Connector 负责批量写入。Flink 的 Checkpoint 机制天然保证了“至少一次”的语义,任务挂掉重启后可以自动从最近一次 Checkpoint 恢复,不用自己维护消费位点。此外 Flink 生态对 JSON、数据库连接器、ES 都有现成的 Connector,开发成本低很多。
1.2 从同步模式看三种方案的差异
为了更直观地判断选型,我把三个方案在几个维度的表现列了一张表。这个表也是我当时给团队汇报时用的,直接决定了大方向。
| 对比维度 | DataX | Canal + 自研消费 | FlinkCDC |
|---|---|---|---|
| 同步模式 | 定时全量/增量 | 实时增量 | 全量 + 实时增量 |
| 秒级延迟 | 无法保证 | 可以 | 可以 |
| 断点续传 | 需要自行设计 | 需要自行维护位点 | Checkpoint 自动恢复 |
| 开发成本 | 低 | 高 | 中 |
| 对源库压力 | 大 | 小 | 小 |
| 数据转换能力 | 弱 | 需要自研 | 强大,支持 SQL/DataStream |
“全量 + 实时增量”是 FlinkCDC 最吸引我的一点。很多存量表已经存在大量历史数据,如果用 Canal,你需要先跑一次历史全量,再切换增量,衔接阶段很容易丢数据。FlinkCDC 的 StartupOptions.initial() 模式会把历史数据先读一遍,再无缝切换到 Binlog 增量,中间不需要人工干预,这个体验是其他方案很难比的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:版本匹配是这场实战最大的隐形门槛
2.1 官方兼容矩阵并不够用
很多人一上来就写代码,结果反复编译报错,最大的问题出在版本匹配上。FlinkCDC、Flink、ES Connector 这三者的版本必须放在一起考虑,单看某一方的文档很容易踩坑。我最终的选型组合是:Flink 1.17.2 + FlinkCDC 2.4.1 + ES 7.17.8 + MySQL 8.0。这个组合我从 2023 年底用到现在,稳定运行了大半年,中间只有一次是因为服务器磁盘写满导致任务挂掉,数据层面没有出过问题。
为什么不建议用 FlinkCDC 2.3 以前的版本?因为 2.3 之前的 MySQL CDC 基于旧的 TableSource 实现,对并行读取支持不好,而且和 Flink 1.15+ 的兼容性有坑。2.4 版本开始,增量快照框架已经比较成熟,可以支持多并行度读取多个分片,性能提升明显。ES Connector 的版本则建议和 Flink 主版本保持一致,比如 Flink 1.17 就选 flink-connector-elasticsearch7:1.17.2,混搭版本往往在序列化器上出问题。
2.2 MySQL Binlog 参数配置
要让 FlinkCDC 正常工作,前提是 MySQL 已经开启 Binlog 并且格式正确。我犯过的第一个低级错误是直接在线上库改配置,结果 MySQL 必须重启才能生效,直接在业务高峰期把订单服务搞出了一个分钟级抖动。所以如果你是从零搭建,最好在初始化数据库时就把下面这些参数配好,不要等到要接数据同步了再补。
在 my.cnf 的 [mysqld] 段加上:
ini复制[mysqld]
server-id = 1
log_bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL
gtid_mode = ON
enforce_gtid_consistency = ON
expire_logs_days = 7
binlog_format = ROW 是必须的,因为 FlinkCDC 需要拿到每一行变更前后的完整数据,Statement 格式只能拿到 SQL 语句,无法还原变更内容。binlog_row_image = FULL 同样重要,它保证更新操作时 Binlog 里记录了所有字段的旧值和新值;如果设置成 MINIMAL,Binlog 只记录被修改的字段,主键以外的其他字段拿不到,后续写入
