三年前接手公司数据中台项目时,我面对的第一个难题就是如何实现毫秒级延迟的数据库变更捕获。当时团队评估了多种CDC方案,最终选择了Debezium+Kafka Connect的组合——这个决定在初期确实帮我们快速搭建起了数据管道,但随着业务量从日均百万级激增到上亿级别,这套架构开始暴露出各种致命缺陷。本文将分享我们如何从Debezium迁移到Flink CDC的全过程,包括那些教科书上不会写的"血泪教训"。
2019年启动项目时,团队需要快速构建一个能实时同步MySQL订单数据到数仓的管道。当时主要考虑了三个关键因素:
技术栈匹配度:我们已有成熟的Kafka集群和Kubernetes部署体系,而Debezium作为Kafka Connect的原生插件,部署只需一个配置文件:
yaml复制{
"name": "inventory-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "mysql",
"database.port": "3306",
"database.user": "debezium",
"database.password": "dbz",
"database.server.id": "184054",
"database.server.name": "dbserver1",
"database.include.list": "inventory",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes.inventory"
}
}
快速验证能力:通过Kafka Connect的REST API,我们仅用两天就完成了从零到POC的验证:
bash复制# 启动连接器
curl -X POST -H "Content-Type: application/json" \
--data @connector-config.json \
http://connect-server:8083/connectors
但很快我们就遇到了第一个坑——全量初始化时的锁表问题。当我们需要同步一个500GB的生产库时,Debezium的全局读锁导致线上查询延迟飙升,最终不得不选择在凌晨停机维护窗口操作。
随着业务规模扩大,原有架构开始出现系统性瓶颈:
组件膨胀问题:
| 场景 | 所需组件 | 运维成本 |
|---|---|---|
| 数据转换 | Kafka Streams/KSQL | ★★★★ |
| 状态监控 | Prometheus+Grafana | ★★★ |
| 容错处理 | 自定义死信队列 | ★★ |
性能天花板测试数据:
text复制单分区吞吐量:~8,000 records/second
端到端延迟:~500ms(理想状态)
资源占用:每任务消耗2CPU/4GB内存
最严重的一次事故发生在2021年大促期间,由于Kafka集群网络抖动,Debezium的offset提交失败导致重复消费,最终导致下游订单金额统计出现严重偏差。这次事件促使我们开始严肃评估替代方案。
在技术选型阶段,我们重点测试了Flink CDC 2.2版本的几个关键特性:
无锁快照验证:
FLUSH TABLES WITH READ LOCK性能对比测试:
| 指标 | Debezium+Kafka | Flink CDC |
|---|---|---|
| 吞吐量(rec/s) | 8,000 | 23,000 |
| 延迟(ms) | 500 | 120 |
| CPU占用 | 2 cores | 1.5 cores |
特别令人惊喜的是其精确一次语义的实现。通过以下配置即可保证端到端一致性:
sql复制CREATE TABLE mysql_orders (
id INT,
order_code STRING,
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'connector' = 'mysql-cdc',
'scan.incremental.snapshot.enabled' = 'true',
'server-id' = '5400-5408'
);
发现MySQL的DATETIME类型在转换到Flink TIMESTAMP时存在时区问题,最终采用:
sql复制CAST(CONVERT_TZ(create_time, '+00:00', 'Asia/Shanghai') AS STRING)
通过调整以下参数实现吞吐量提升300%:
yaml复制execution.checkpointing.interval: 10s
parallelism.default: 8
table.exec.source.cdc-events-duplicate: true
抛弃原来的多组件方案,改用Flink原生Metrics系统:
code复制# 关键监控指标
flink_taskmanager_job_latency_source_id=xxx
flink_taskmanager_job_numRecordsIn
开发了混合加载策略:
最大的挑战是Kafka消息格式的兼容,最终采用Schema Registry的兼容模式:
avro复制{
"type": "record",
"name": "Envelope",
"fields": [
{"name": "before", "type": ["null", "Record"]},
{"name": "after", "type": ["null", "Record"]}
]
}
新旧架构对比图:
code复制Debezium时代:
MySQL → Debezium → Kafka → Stream Processing → HBase
Flink CDC时代:
MySQL → Flink CDC → HBase
核心收益指标:
在最近一次全链路压测中,新架构成功支撑了峰值50,000 TPS的流量,期间CPU负载始终保持在70%以下。更宝贵的是,我们终于可以摆脱那些凌晨三点处理Kafka Connect崩溃的on-call了。