Flink cdc写入kafka数据出现null的问题排查与解决

Flink cdc是目前实时同步binlog数据非常方便的工具,今天业务在消费同步的数据发现其中有很多的null数据,经过排查,总结出以下特点:

  1. null数据的出现有一定规律,几乎每个+U(upsert_after)类型的数据前就有一条null数据
  2. 数据在出现null前,同步逻辑做过更改,添加了where语句过滤数据,在此前没有过null数据

首先,我需要确定null数据是什么。查询官方文档可以知道在upsert-kafka中,会把-D(delete)类型数据写成null。


但是我已经通过参数去掉了-D类型数据,并且-D类型不可能这么有规律的出现,因此,这些null数据很大可能是-U类型数据,但是-U类型为什么会变成null呢?通过源码我们可以一探究竟:原来-U写入kafka会被直接设置成-D类型,最终成为一条null的消息体。

static void processLastRowOnChangelog(
            RowData currentRow,
            boolean generateUpdateBefore,
            ValueState<RowData> state,
            Collector<RowData> out) throws Exception {
        RowData preRow = state.value();
        RowKind currentKind = currentRow.getRowKind();
        if (currentKind == RowKind.INSERT || currentKind == RowKind.UPDATE_AFTER) {
            if (preRow == null) {
                // the first row, send INSERT message
                currentRow.setRowKind(RowKind.INSERT);
                out.collect(currentRow);
            } else {
                if (generateUpdateBefore) {
                    preRow.setRowKind(RowKind.UPDATE_BEFORE);
                    out.collect(preRow);
                }
                currentRow.setRowKind(RowKind.UPDATE_AFTER);
                out.collect(currentRow);
            }
            // normalize row kind
            currentRow.setRowKind(RowKind.INSERT);
            // save to state
            state.update(currentRow);
        } else {
            // DELETE or UPDATER_BEFORE
            if (preRow != null) {
                // always set to DELETE because this row has been removed
                // even the the input is UPDATE_BEFORE, there may no UPDATE_AFTER after it.
                preRow.setRowKind(RowKind.DELETE);
                // output the preRow instead of currentRow,
                // because preRow always contains the full content.
                // currentRow may only contain key parts (e.g. Kafka tombstone records).
                out.collect(preRow);
                // clear state as the row has been removed
                state.clear();
            }
            // nothing to do if removing a non-existed row
        }
    }

 

基于以上可以做一个结论:null数据就是-U(upsert_befor)类型数据,并且是添加where条件后引入的。通过测试也可以验证在没有where条件时,写入kafka的数据并不会出现null。那么为什么同样的-U数据,只会在有where语句时才会出现在kafka中呢。最终通过查看执行计划一切真相大白!

上面的图是不加where语句时flink-cdc的执行计划,和加where语句执行计划的区别就是多了301-DorpUpdateBefore这个算子。原来flink-cdc在upsert-kafka模式下,执行计划在没有where语句时会进行优化,去掉所有的-U数据,这就合理解释了where条件导致的数据差异!

最后,解决kafka中null消息,只需要在flink sql中过滤掉binlog数据类型是-U的数据即可!

Flink CDCKafka 关联紧密,常结合使用以构建实时数据处理系统。 ### 结合使用 - **数据同步方案**:使用 Flink CDC 将 MySQL 的 CDC 数据(Avro 格式或 Json 格式)接入到 Kafka,然后通过 Flink Hudi Connector 将摄取的 CDC 数据写入到 Hudi 表中,整个链路由 Confluent Schema Registry 控制 Schema 的变更。例如,有《CDC 实时入湖方案:MySQL > Flink CDC > Kafka > Hudi》相关方案,其中一种是基础的将 MySQL 的 CDC 数据以 Json 格式接入 Kafka写入 Hudi 表,适合作为 POC 方案快速搭建 CDC 实时处理链路;还有增强版方案,在打通从源端数据库到 Hudi 表完整链路的前提下,额外做了一些工作 [^3][^4]。 - **多源合并和下游同步更新**:可以实现 Flink CDCKafka 进行多源合并和下游同步更新,也能完成整库/多表同步,如 Flink CDC 整库同步(含代码,mysql -> greenplumn 场景)、Mysql 整库同步等,还能动态地增加新的同步表到同一个作业中 [^1]。 - **数据查看**:Flink CDC 作业提交后,可在 Kafka 中查看写入的消息。由于写入的是 Avro 格式,使用 kafka - console - consumer 直接查看看到的是 Avro 的二进制数据,应使用 Confluent 提供的 kafka - avro - console - consumer 来查看。给出的示例脚本展示了如何连接到 Kafka 代理和 Schema 注册表,读取 Avro 数据并反序列化消息 [^2]。 ### 对比 Flink CDCKafka 功能不同。Flink CDC 主要用于捕获数据库的变更数据,能够实时监测数据库的变化并将这些变更数据提取出来,如捕获 MySQL 的 CDC 数据。而 Kafka 是一个分布式流处理平台,主要用于高吞吐量的实时数据传输和存储,可作为数据的缓冲区,接收 Flink CDC 提取的变更数据,并将数据分发给下游的处理系统,如 Hudi 表 [^3][^4]。 ### 代码示例 Flink SQL 结合 Kafka 进行关联表数据处理示例: ```sql -- insert into test2_kafka select a1.id,a1.`name`,a1.create_time,a1.update_time,a1.hobby,a2.`name` from test1_source as a1 join test4 as a2 on a1.id = a2.id; ``` 该示例展示了将 Flink SQL 写入 Kafka 后进行关联表数据写入到 sink 端的情况 [^5]。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值