java 实现 flink cdc 读 mysql binlog 按表写入kafka不同topic

一.背景

在企业数字化转型进入深水区的当下,数据的 "实时性" 与 "精细化流转" 已成为支撑业务创新的核心诉求。MySQL 作为企业核心业务数据库(如交易系统、用户中心、订单管理等),存储着关键业务数据,这些数据的变更(新增、修改、删除)需要被实时捕获、传输,以支撑实时监控、数据同步、实时报表、下游系统联动等场景。然而,传统数据同步方案逐渐难以适配业务对 "低延迟、高可靠、精细化分发" 的核心需求,痛点日益凸显:

传统数据同步多依赖定时全量查询、触发器等方式,存在明显局限:定时查询无法满足实时性要求,数据延迟常达分钟级甚至小时级,难以支撑即时决策类业务;触发器则会侵入业务数据库,增加数据库性能开销,且容错性差,易因数据异常导致同步中断。同时,即便采用 Binlog 解析工具捕获数据变更,传统方案往往将所有表的变更数据汇总写入单一存储或消息队列 Topic,导致下游消费端需花费大量精力筛选目标表数据,数据流转效率低、耦合度高,且难以应对多下游系统差异化的数据消费需求。

在此背景下,"Flink CDC + MySQL Binlog + Kafka 分 Topic" 的协同架构成为解决上述痛点的最优解,各组件各司其职、形成高效闭环:

  1. MySQL Binlog 作为数据变更源头:Binlog 是 MySQL 自带的二进制日志,完整记录了数据库表的所有变更操作(DML/DDL),是捕获数据实时变更的核心载体,无需侵入业务代码,对原系统性能影响极小;
  2. Flink CDC 作为实时数据捕获引擎:Flink CDC(Change Data Capture)基于 Flink 流处理框架开发,专门用于实时捕获数据库变更数据,支持 Exactly-Once 语义,具备高吞吐、低延迟、高容错的特性。它可直接解析 MySQL Binlog,无需依赖中间件,能实时提取各表的变更数据,并支持数据清洗、格式转换等基础处理,是连接 MySQL 与 Kafka 的核心桥梁;
  3. Kafka 按表分 Topic 作为数据分发枢纽:Kafka 凭借高吞吐、低延迟、高可用的特性,成为实时数据流分发的核心组件。按 MySQL 表名拆分不同 Kafka Topic,可实现数据的 "精细化分发"------ 每个表的变更数据独立存储在专属 Topic 中,下游系统(如实时计算引擎、数据仓库、业务应用)可按需订阅目标 Topic,无需筛选无效数据,极大提升消费效率,同时降低系统耦合度,适配多下游差异化需求。

Java 作为 Flink、Kafka 生态的核心开发语言,具备完善的 API 支持、成熟的企业级实践与丰富的生态工具链,能够确保架构的稳定性、可扩展性与可维护性。因此,采用 Java 实现 "Flink CDC 读 MySQL Binlog 按表写入 Kafka 不同 Topic" 的方案,本质是构建一套 "实时变更捕获 - 精细化数据分发 - 高可靠流转" 的端到端数据链路。该方案可广泛应用于实时数据仓库增量同步、业务系统跨库实时联动、实时监控告警、用户行为实时分析等场景,帮助企业打破数据流转的 "实时壁垒" 与 "耦合瓶颈",实现核心业务数据的高效、精准流转,为数据驱动决策提供实时、可靠的数据支撑。

二.具体实现

1.创建java工程,引入依赖

复制代码
        <dependency>
            <groupId>com.ververica</groupId>
            <artifactId>flink-connector-mysql-cdc</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-java</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-java</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-clients</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-connector-kafka</artifactId>
            <version>3.0.2-1.18</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

2.定义cdc 源

复制代码
        MySqlSource<String> sourceFunction = MySqlSource.<String>builder()
                .hostname(mysql地址)
                .port(mysql端口)
                .scanNewlyAddedTableEnabled(true)
                .username(mysql用户)
                .password(mysql密码)
                .databaseList(数据库1,数据库2)
                .tableList(数据库1.表1,数据库1.表2... ...)
                .deserializer(new JsonDebeziumDeserializationSchema(false, configs))
                .startupOptions(startupOptions)
                .build();
        DataStreamSource<String> streamSource = env.fromSource(sourceFunction, WatermarkStrategy.noWatermarks(), "MySQL Source");

2.转换数据为Tuple2<topic名称, binlog数据>格式流

复制代码
DataStream<Tuple2<String, JSONObject>> resultStream = streamSource.map(new MapFunction<String, Tuple2<String, JSONObject>>() {
            @Override
            public Tuple2<String, JSONObject> map(String value) throws Exception {

                JSONObject data = JSONObject.parseObject(value);

                if(tableTopicMapConfigs.containsKey(data.getJSONObject("source").getString("table"))){
                    return new Tuple2<>(tableTopicMapConfigs.getString(data.getJSONObject("source").getString("table")), data);
                }else{
                    throw new Exception("未找到对应的topic");
                }
            }
        });

3.定义动态topic序列化结构

复制代码
public class DynamicTopicsSerializationSchema implements KeyedSerializationSchema<Tuple2<String,JSONObject>> {


    @Override
    public byte[] serializeKey(Tuple2<String,JSONObject> value) {
        String pk = value.f1.hashCode()+"";

        return (pk).getBytes();
    }

    @Override
    public byte[] serializeValue(Tuple2<String,JSONObject> value) {
        String values = value.f1.toString();
        return values.getBytes();

    }

    @Override
    public String getTargetTopic(Tuple2<String,JSONObject> value) {

        return value.f0;

    }
}

4.定义动态分区

复制代码
public class DynamicTopicsKafkaPartitioner extends FlinkKafkaPartitioner<Tuple2<String,JSONObject>> {

    private static Logger logger = LoggerFactory.getLogger(DynamicTopicsKafkaPartitioner.class);


    @Override
    public int partition(Tuple2<String,JSONObject> pairValue, byte[] key, byte[] value, String topic, int[] partitions) {
            return Math.abs(pairValue.f1.hashCode() % partitions.length);
    }


    public static void main(String[] args) {

    }
}

5.定义kafka sink

复制代码
Properties producerConfig = new Properties();
        producerConfig.setProperty(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,kafka地址);
        producerConfig.setProperty(ProducerConfig.COMPRESSION_TYPE_CONFIG, "zstd");
        producerConfig.put("sink.delivery-guarantee","exactly-once");

        FlinkKafkaProducer flinkKafkaProducer = new FlinkKafkaProducer(
                "",
                new DynamicTopicsSerializationSchema(),
                producerConfig,
                java.util.Optional.of(new DynamicTopicsKafkaPartitioner()),
                FlinkKafkaProducer.Semantic.EXACTLY_ONCE,
                FlinkKafkaProducer.DEFAULT_KAFKA_PRODUCERS_POOL_SIZE
        );

        resultStream.addSink(flinkKafkaProducer);
相关推荐
Arva .37 分钟前
Spring Boot自动配置原理
java·spring boot·后端
寻星探路38 分钟前
Java EE初阶启程记15---文件操作和IO
java·java-ee
阿巳helloWorld39 分钟前
SpringMVC底层流程解析
java·开发语言
学习中的阿陈39 分钟前
flume安装
大数据·flume
heartbeat..40 分钟前
介绍java中常用于处理 Excel 文件的Apache POI
java·apache·excel·poi
八饱粥40 分钟前
excel数据导入mysql数据库
数据库·mysql·excel
路边草随风40 分钟前
java 实现 flink 读 kafka 写 iceberg
java·flink·kafka
低客的黑调42 分钟前
Spring MVC 全面详解:原理、组件、实战与高级特性
java·spring·mvc
STARFALL00142 分钟前
spring mvc 自定义Converter 设置
java·spring·mvc