Flink CDC系列之:Kafka Sink 的序列化器PipelineKafkaRecordSerializationSchema

这是一个 Flink CDC Kafka Sink 的序列化器,负责将 Change Data Capture (CDC) 事件序列化为 Kafka 消息。

核心功能

这个类实现了 KafkaRecordSerializationSchema,专门用于将 CDC 事件序列化为 Kafka 的 ProducerRecord。

关键组件
配置参数

  • partition: 分区策略(0分区或null)
  • keySerialization: Key 序列化器
  • valueSerialization: Value 序列化器
  • unifiedTopic: 统一主题名称
  • addTableToHeaderEnabled: 是否添加表信息到 Header
  • customHeaders: 自定义 Header 键值对
  • mappingRuleString: 表到主题的映射规则

构造函数逻辑

java 复制代码
PipelineKafkaRecordSerializationSchema(
    PartitionStrategy partitionStrategy,    // 分区策略
    SerializationSchema<Event> keySerialization,    // Key序列化
    SerializationSchema<Event> valueSerialization,  // Value序列化
    String unifiedTopic,                    // 统一主题
    boolean addTableToHeaderEnabled,        // 表头启用
    String customHeaderString,              // 自定义头字符串
    String mappingRuleString)               // 映射规则
  • 解析自定义 Header 字符串(格式:key1:value1;key2:value2)
  • 根据分区策略设置分区号

核心方法解析

serialize() - 序列化方法

java 复制代码
public ProducerRecord<byte[], byte[]> serialize(Event event, KafkaSinkContext context, Long timestamp) {
    // 1. 序列化 Key 和 Value
    ChangeEvent changeEvent = (ChangeEvent) event;
    final byte[] keySerialized = keySerialization.serialize(event);
    final byte[] valueSerialized = valueSerialization.serialize(event);
    
    // 2. 跳过 SchemaChangeEvent
    if (event instanceof SchemaChangeEvent) {
        return null;
    }
    
    // 3. 推断主题名称
    String topic = inferTopicName(changeEvent.tableId());
    
    // 4. 构建 Record Headers
    RecordHeaders recordHeaders = new RecordHeaders();
    
    // 添加表信息到 Header
    if (addTableToHeaderEnabled) {
        recordHeaders.add(new RecordHeader(NAMESPACE_HEADER_KEY, namespace.getBytes(UTF_8)));
        recordHeaders.add(new RecordHeader(SCHEMA_NAME_HEADER_KEY, schemaName.getBytes(UTF_8)));
        recordHeaders.add(new RecordHeader(TABLE_NAME_HEADER_KEY, tableName.getBytes(UTF_8)));
    }
    
    // 添加自定义 Header
    if (!this.customHeaders.isEmpty()) {
        for (Map.Entry<String, String> entry : customHeaders.entrySet()) {
            recordHeaders.add(new RecordHeader(entry.getKey(), entry.getValue().getBytes(UTF_8)));
        }
    }
    
    // 5. 创建 ProducerRecord
    return new ProducerRecord<>(
        topic, partition, null, keySerialized, valueSerialized, recordHeaders);
}

inferTopicName() - 主题推断逻辑

java 复制代码
private String inferTopicName(TableId tableId) {
    return tableIdToTopicCache.computeIfAbsent(tableId, (table -> {
        // 优先使用统一主题
        if (unifiedTopic != null && !unifiedTopic.isEmpty()) {
            return unifiedTopic;
        }
        // 其次使用映射规则匹配
        if (selectorsToTopicMap != null && !selectorsToTopicMap.isEmpty()) {
            for (Map.Entry<Selectors, String> entry : selectorsToTopicMap.entrySet()) {
                if (entry.getKey().isMatch(tableId)) {
                    return entry.getValue();
                }
            }
        }
        // 默认使用表名作为主题
        return table.toString();
    }));
}

open() - 初始化方法

java 复制代码
public void open(SerializationSchema.InitializationContext context, KafkaSinkContext sinkContext) {
    // 解析映射规则
    this.selectorsToTopicMap = KafkaSinkUtils.parseSelectorsToTopicMap(mappingRuleString);
    // 初始化缓存
    this.tableIdToTopicCache = new HashMap<>();
    // 初始化值序列化器
    valueSerialization.open(context);
}

重要特性

主题映射策略(优先级顺序)

  • 统一主题: 所有表数据发送到同一个主题
  • 规则映射: 根据表选择器规则映射到不同主题
  • 表名主题: 默认使用表名作为主题名

Header 信息丰富

  • 表结构信息: namespace, schemaName, tableName
  • 自定义 Header: 用户定义的任意键值对
  • 便于下游处理: 消费者可以根据 Header 识别数据来源

数据过滤

  • 跳过 SchemaChangeEvent: 只处理数据变更事件
  • 保留 ChangeEvent: 数据增删改事件

性能优化

  • 缓存机制: 表名到主题的映射缓存,避免重复计算

懒加载: 在 open 方法中初始化资源

应用场景

这个序列化器主要用于:

  • CDC 数据管道: 将数据库变更实时同步到 Kafka
  • 多租户架构: 不同表的数据路由到不同主题
  • 数据湖入湖: 为下游数据湖提供结构化的变更数据
  • 微服务数据同步: 各服务订阅相关表的变更数据
相关推荐
StarRocks_labs2 天前
当大模型调用进入执行引擎:StarRocks AI Function 全新能力解析
数据库·starrocks·sql·ai·pipeline·数据处理·join
FungLeo15 天前
成为全栈·Node 后端篇·数据迁移:schema 变更如何不弄脏线上数据
sqlite·orm·schema·d1·node 后端·drizzle
韦东东16 天前
规则 or Agent 驱动:一个合同审查系统的产品设计与工程拆解
pipeline·agent·合同审查·模型与规则
tianyuanwo17 天前
Jenkins Pipeline 沙箱与非沙箱:CPS、序列化与白名单的深度解读(含 `take()` 与 `subList()` 实战对比)
pipeline·jenkins·groovy·take·sublist
StarRocks_labs20 天前
基于 Fluss、Paimon 与 StarRocks 构建淘天集团湖流一体数据链路
starrocks·olap·schema·paimon·fluss·湖流一体
StarRocks_labs21 天前
StarRocks 4.1:聚焦生产实践,持续降低运维复杂度
运维·starrocks·iceberg·schema·物化视图·tablet·存算分离架构
滨哥GPT24 天前
Codex修改数据库后项目启动失败怎么办?Migration、Schema与数据结构排查
数据库·ai编程·开发工具·schema·codex
不动明王19841 个月前
Presto 查询引擎内核详解:分布式规划机制
pipeline·mpp·presto·查询引擎内核·分布式规划
heimeiyingwang1 个月前
【CI/CD·Jenkins篇】Pipeline 基础:Declarative 与 Scripted 语法详解
ci/cd·pipeline·jenkins
Akirweiwen4 个月前
约束显化:通过意图协议将 LLM 不可突破边界转化为机器可读契约
llm·schema·design system