Kafka Connect vs Flink CDC——CDC到Kafka用哪个方案更稳?
本文目录
先说结论
一句话决策:纯Kafka生态选Kafka Connect(运维简单、原生集成);已有Flink集群+做ETL选Flink CDC(一体化、灵活)。
两者本质区别:Kafka Connect是"配置驱动的转储",Flink CDC是"作业驱动的流处理"。前者是基础设施,后者是计算框架。
不是非此即彼:大公司经常并存——稳定的核心库用Kafka Connect保稳定,需要复杂处理的用Flink CDC做ETL。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
"CDC数据进Kafka"这个看似简单的需求,业内有两套主流方案:Kafka Connect(Debezium Connector)和Flink CDC。两者表面功能相似,底层架构差异很大。这道题面试官想看的不是"哪个更好",而是你能不能从架构、运维、可靠性、扩展性多个维度做出有理由的选型。
业务场景:从Connect切到Flink CDC的取舍
一个数据平台最初CDC全用Kafka Connect Debezium,后来部分场景切到了Flink CDC。原因不是"Flink CDC更好",而是有一类需求Kafka Connect扛不住——CDC数据进Kafka前需要做复杂转换(字段加密脱敏、关联维度表、过滤敏感库),这种场景Kafka Connect的SMT(Single Message Transform)能力很弱,最后退化成"Connect只采集→Flink再处理"两段链路,多了一倍延迟和成本。
方案一:Kafka Connect + Debezium
Kafka Connect是Kafka官方的连接框架,Debezium是基于它的CDC实现。优势是开箱即用、跟Kafka集群同生命周期、无需额外计算资源。
// 注册一个MySQL CDC connector
POST /connectors
{
"name": "mysql-orders-source",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"tasks.max": "1",
"database.hostname": "mysql-readonly",
"database.port": "3306",
"database.user": "debezium",
"database.password": "****",
"database.server.id": "5400",
"topic.prefix": "mysql.order_db",
"table.include.list": "order_db.orders,order_db.payments",
"schema.history.internal.kafka.bootstrap.servers": "kafka:9092",
"schema.history.internal.kafka.topic": "schema_history.order_db",
"snapshot.mode": "initial",
// SMT: 简单转换可以做
"transforms": "unwrap,routing",
"transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",
"transforms.routing.type": "org.apache.kafka.connect.transforms.RegexRouter",
"transforms.routing.regex": "mysql.order_db.(.*)",
"transforms.routing.replacement": "ods_$1"
}
}
适用场景:纯转储到Kafka、不做复杂处理、运维倾向"声明式配置"。
不适用:需要关联多表/做ETL/字段脱敏;没有Kafka Connect集群基础设施。
方案二:Flink CDC
Flink CDC本质是"用Flink把Debezium内嵌进作业里",整个CDC流程就是一个Flink Job。优势是可以在采集的同时做任意复杂处理,劣势是要维护Flink集群。
-- Flink SQL一段搞定:CDC采集+维度关联+脱敏+写Kafka
CREATE TABLE orders_cdc (
id BIGINT, user_id BIGINT, phone STRING, amount DECIMAL(10,2),
PRIMARY KEY (id) NOT ENFORCED
) WITH ('connector' = 'mysql-cdc', ...);
-- 维度表(用户中心)
CREATE TABLE dim_users (
user_id BIGINT, vip_level INT, country STRING,
PRIMARY KEY (user_id) NOT ENFORCED
) WITH ('connector' = 'jdbc', ...);
-- Kafka sink
CREATE TABLE orders_kafka (
id BIGINT, user_id BIGINT, phone_masked STRING,
amount DECIMAL(10,2), vip_level INT, country STRING
) WITH ('connector' = 'kafka', 'topic' = 'ods_orders_enriched', ...);
-- 一段INSERT完成: CDC采集 + 关联维度 + 字段脱敏 + 写Kafka
INSERT INTO orders_kafka
SELECT
o.id, o.user_id,
CONCAT(SUBSTR(o.phone, 1, 3), '****', SUBSTR(o.phone, 8)) AS phone_masked,
o.amount, u.vip_level, u.country
FROM orders_cdc o
LEFT JOIN dim_users FOR SYSTEM_TIME AS OF o.proctime u ON o.user_id = u.user_id;
适用场景:已有Flink集群、需要在采集时做ETL、希望减少链路跳数。
两方案核心差异
| 维度 | Kafka Connect | Flink CDC |
|---|---|---|
| 架构定位 | Kafka基础设施 | Flink作业 |
| 运维方式 | REST API管理connector | 提交Flink作业 |
| 资源占用 | Connect Worker进程 | Flink TM/JM |
| 容错恢复 | task级restart | Checkpoint+Savepoint |
| 处理能力 | 弱(只SMT) | 强(完整Flink SQL) |
| Schema演进 | 支持(Avro+Registry) | 支持(2.4+) |
| 扩展性 | 动态加tasks.max | 改作业并行度+rescale |
| 监控生态 | JMX+Connect REST | Flink UI+Metrics |
| 典型用法 | 采集即转储 | 采集+转换+多sink |
场景化选型
▶ 选 Kafka Connect 的场景:
- 已有Kafka集群,Connect Worker部署简单
- 只是"原样转储"到Kafka,无ETL需求
- 团队倾向声明式配置,不想写代码
- 跨语言/多团队消费,Avro+Registry成熟
- SaaS产品(如Confluent Cloud)集成方便
▶ 选 Flink CDC 的场景:
- 已有Flink集群,不想再维护Connect
- 采集时需要关联维度表/字段脱敏/过滤
- 需要写多个Sink(Kafka+Iceberg+Hologres)
- 已经用Flink SQL,人才储备友好
- 希望全量+增量自动衔接(Connect需要单独snapshot配置)
▶ 混合方案(大公司常见):
- 核心库稳定无ETL → Kafka Connect
- 需要实时融合的库 → Flink CDC
- 团队基础设施: Kafka Connect托管 + Flink计算平台
面试高频追问
追问一:Kafka Connect的Exactly-Once怎么保证?
Connect框架本身保证source connector的at-least-once(offset commit到Kafka的__consumer_offsets)。Exactly-Once需要source connector自己实现幂等输出——Debezium MySQL Connector通过把binlog position存在Kafka source topic的header里,重启时从这个position继续,不会重复发送。但下游消费者还是要做幂等,因为重启窗口可能有重复。Connect 2.x开始支持EOS sink(精确一次写入sink),source侧仍依赖connector实现。
追问二:两者的Schema管理有什么差异?
Kafka Connect天然集成Confluent Schema Registry——connector发出的每条消息都带schema id,下游解析时从Registry取schema。Schema演进通过Registry的兼容性策略管控(FORWARD/BACKWARD)。Flink CDC的schema管理在2.4之前比较弱(Schema硬编码在DDL里),2.4+引入Pipeline模式才支持自动schema evolution。生产上如果schema变更频繁,Kafka Connect+Registry的方案更成熟。
追问三:Flink CDC的Source会不会比Connect对源库压力更大?
两者底层都是Debezium,对源库的binlog dump压力相同。差异在snapshot阶段:Kafka Connect Debezium默认要锁全局或锁表(高风险),Flink CDC 2.x无锁snapshot更友好。Flink CDC的并行度(server-id范围)可能产生多个并行snapshot reader,理论上对源库IO更高,但通过限流和走从库可以控制。生产上两者的源库压力都可控,关键是不连主库。
实战踩坑:Connect任务静默失败导致数据停止流转
有次发现下游Kafka消费者lag一直为0,本来以为是好事,结果业务报表少了一天数据——查Kafka Connect的REST API才发现connector状态是FAILED但没有任何告警。Connect默认不会主动告警,只能通过API轮询。后来加了Prometheus监控+JMX exporter,把connector状态、task状态、binlog position作为关键指标,FAILED超过60秒就钉钉告警。
# Connect监控API(必须自己定时轮询)
curl -s http://kafka-connect:8083/connectors/mysql-orders-source/status | jq
{
"name": "mysql-orders-source",
"connector": { "state": "RUNNING" },
"tasks": [
{ "id": 0, "state": "FAILED", // ← 关键!静默失败
"trace": "Cannot find binlog file: mysql-bin.001234..." }
]
}
# 加Prometheus jmx exporter
java -javaagent:jmx_prometheus_javaagent.jar=8080:config.yaml \
-jar connect-distributed.sh ...
# 关键告警指标
# kafka_connect_connector_status{state="FAILED"} > 0 持续60s → P0
# kafka_connect_task_failed_count > 0 → P1
# debezium_mysql_milliseconds_behind_source > 60000 → P2
解决方案:Kafka Connect监控不能依赖默认行为,必须自己加Prometheus监控+主动告警。同时connector要配restart.policy(Connect 3.x支持自动重试),减少人工介入。这个坑出过一次后我把所有Connect集群都加了完整监控。
总结
Kafka Connect和Flink CDC不是"哪个更好"的问题,是"哪个适合"的问题。Connect适合纯转储的稳定基础设施,Flink CDC适合需要在采集时做处理的场景。大公司经常并存,核心稳定库用Connect、需要融合的用Flink CDC。面试时讲"两者定位差异+场景选型+混合方案",比说"Flink CDC更先进"分高得多。
下一篇聊一个很烦的实战题:历史数据补采跑了8小时,怎么设计回溯采集机制?
你们公司CDC到Kafka用的哪个方案?踩过哪些坑?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长