Kafka: Connect 实战之MySQL 数据双向同步集成方案

Source Connector 配置:MySQL → Kafka 数据同步

1 ) 动态添加 Connector

  • 通过 API 创建 JDBC Source Connector,从 MySQL 表 users 实时捕获数据变更。

  • 关键配置参数:

    json 复制代码
    {
      "name": "mysql-source-users",  // Connector 唯一标识 
      "config": {
        "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
        "connection.url": "jdbc:mysql://192.168.0.140:3306/kafka_study",
        "connection.user": "root",
        "connection.password": "123456",
        "table.whitelist": "users",  // 监听的表
        "mode": "incrementing",       // 增量模式 
        "incrementing.column.name": "id",  // 自增列(用于识别新数据)
        "topic.prefix": "imc-mysql-",      // 生成 Topic 的格式(如 imc-mysql-users)
        "tasks.max": "1"
      }
    }
  • 执行命令:

bash 复制代码
curl -X POST http://localhost:8083/connectors \
     -H "Content-Type: application/json" \
     -d @jdbc-source-config.json  

✅ 响应状态码 201 表示创建成功

2 ) 验证数据同步

  • 向 MySQL 表 users 插入数据:

    sql 复制代码
    INSERT INTO users (name, age) VALUES ('Allen', 18);  
    • 消费 Kafka Topic 验证数据:
    bash 复制代码
    kafka-console-consumer --bootstrap-server localhost:9092 \
                           --topic imc-mysql-users \
                           --from-beginning  
  • 输出示例:

    json 复制代码
    {
      "schema": { /* Avro Schema */ },
      "payload": {
        "id": 1,
        "name": "Allen",
        "age": 18
      }
    }  

Sink Connector 配置:Kafka → MySQL 数据回写

1 ) 创建 Sink Connector

  • 将 Kafka Topic imc-mysql-users 的数据写入 MySQL 表 users_back

    json 复制代码
    {
      "name": "mysql-sink-users-back",  
      "config": {
        "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",
        "connection.url": "jdbc:mysql://192.168.0.140:3306/kafka_study",
        "connection.user": "root",
        "connection.password": "123456",
        "topics": "imc-mysql-users",  // 监听的 Topic
        "table.name.format": "users_back",  // 目标表 
        "insert.mode": "upsert",            // 写入模式(插入/更新)
        "pk.mode": "record_key",            // 主键模式
        "pk.fields": "id"                   // 主键字段
      }
    }  
  • 执行命令:

    bash 复制代码
    curl -X POST http://localhost:8083/connectors \
         -H "Content-Type: application/json" \
         -d @jdbc-sink-config.json  

2 ) 验证回写结果

  • 查询 MySQL 表 users_back

    sql 复制代码
    SELECT * FROM users_back;  -- 应包含与 `users` 相同的数据  
  • 若更新 users 表数据,users_back 将自动同步(upsert 模式生效)。

Kafka Connect 核心概念解析

1 ) Connector 与 Task

  • Connector:管理数据同步任务的逻辑单元(如 mysql-source-users)。

  • Task:实际执行数据搬运的物理线程,一个 Connector 可启动多个 Task 并行处理。

  • Rebalance 机制:当 Task 故障时,自动将分区分配给健康 Task(如下图所示):

    tree 复制代码
    [Task1, Task2, Task3] → Task2 故障 → Rebalance → [Task1, Task3]  

2 ) Converter 的作用

  • 数据格式转换:Source Connector 从 MySQL 读取数据后,需通过 Converter(如 JsonConverter)序列化为 Kafka 兼容格式(如 JSON/Avro)。

  • Sink Connector 的逆过程:将 Kafka 数据反序列化后写入目标库。

  • 配置示例:

    properties 复制代码
    key.converter=org.apache.kafka.connect.json.JsonConverter  
    value.converter=org.apache.kafka.connect.json.JsonConverter  

3 ) 部署模式对比

模式 Standalone Distributed
适用场景 开发/测试 生产环境
高可用 不支持 支持(多节点故障转移)
扩展性 单节点 水平扩展

生产环境注意事项

1 ) 局限性

  • Schema 管理复杂:需配套 Schema Registry 确保数据兼容性。
  • 删除数据同步:默认不处理源表删除操作(需自定义逻辑)。

2 ) 替代方案建议

  • 复杂场景推荐 Elasticsearch Logstash 或 Debezium,其在 CDC(Change Data Capture)领域更成熟。

工程示例:基于 NestJS 的 Kafka 集成方案

目标:替代 Java 技术栈,提供全链路 NestJS 实现

1 ) 方案 1:NestJS 作为 Kafka 生产者/消费者

typescript 复制代码
// 安装依赖  
npm install @nestjs/microservices kafkajs  
 
// src/kafka/kafka.module.ts  
import { Module } from '@nestjs/common';  
import { ClientsModule, Transport } from '@nestjs/microservices';  
 
@Module({  
  imports: [  
    ClientsModule.register([  
      {  
        name: 'KAFKA_SERVICE',  
        transport: Transport.KAFKA,  
        options: {  
          client: {  
            brokers: ['localhost:9092'],  
          },  
          consumer: {  
            groupId: 'nestjs-consumer-group',  
          },  
        },  
      },  
    ]),  
  ],  
  exports: [ClientsModule],  
})  
export class KafkaModule {}  
 
// src/user/user.service.ts(生产者示例)  
import { Injectable } from '@nestjs/common';  
import { InjectRepository } from '@nestjs/typeorm';  
import { Repository } from 'typeorm';  
import { User } from './user.entity';  
import { ClientKafka } from '@nestjs/microservices';  
 
@Injectable()  
export class UserService {  
  constructor(  
    @InjectRepository(User) private userRepository: Repository<User>,  
    @Inject('KAFKA_SERVICE') private kafkaClient: ClientKafka,  
  ) {}  
 
  async createUser(userData: Omit<User, 'id'>) {  
    const user = this.userRepository.create(userData);  
    await this.userRepository.save(user);  
    // 发送消息到 Kafka  
    this.kafkaClient.emit('imc-mysql-users', {  
      key: user.id.toString(),  
      value: JSON.stringify(user),  
    });  
    return user;  
  }  
}  
 
// src/user/user.consumer.ts(消费者示例)  
import { Controller } from '@nestjs/common';  
import { EventPattern, Payload } from '@nestjs/microservices';  
 
@Controller()  
export class UserConsumer {  
  @EventPattern('imc-mysql-users')  
  async handleUserEvent(@Payload() message: { value: string }) {  
    const user = JSON.parse(message.value);  
    console.log('Received user data:', user);  
    // 可在此写入 users_back 表  
  }  
}  

2 ) 方案 2:NestJS 监控 Kafka Connect API

typescript 复制代码
// src/connect/connect.service.ts  
import { Injectable } from '@nestjs/common';  
import { HttpService } from '@nestjs/axios';  
 
@Injectable()  
export class ConnectService {  
  constructor(private httpService: HttpService) {}  
 
  async createConnector(config: object) {  
    const response = await this.httpService.  
      post('http://localhost:8083/connectors', config)  
      .toPromise();  
    return response.data;  
  }  
 
  async listConnectors() {  
    const response = await this.httpService.  
      get('http://localhost:8083/connectors')  
      .toPromise();  
    return response.data;  
  }  
}  

3 ) 方案 3:自定义 Connector 替代方案(简化版)

适用场景:需灵活控制数据流转逻辑

typescript 复制代码
// src/task/task-scheduler.service.ts  
import { Injectable } from '@nestjs/common';  
import { Cron } from '@nestjs/schedule';  
import { UserService } from '../user/user.service';  
 
@Injectable()  
export class TaskSchedulerService {  
  constructor(private userService: UserService) {}  
 
  @Cron('*/30 * * * * *') // 每 30 秒执行  
  async syncUsersToBackup() {  
    const users = await this.userService.findAll();  
    // 批量写入 users_back 表(省略 ORM 操作)  
    console.log(`Synced ${users.length} users to backup table`);  
  }  
}  

配置优化与周边工具

1 ) Kafka 命令补充

  • 查看 Connector 状态:

    bash 复制代码
    curl http://localhost:8083/connectors/mysql-source-users/status  
  • 重启 Task:

    bash 复制代码
    curl -X POST http://localhost:8083/connectors/mysql-source-users/tasks/0/restart  

2 )Schema Registry 集成(确保数据一致性)

yaml 复制代码
# docker-compose.yml 片段  
schema-registry:  
  image: confluentinc/cp-schema-registry:7.0.1  
  depends_on: [kafka]  
  ports: ["8081:8081"]  
  environment:  
    SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:9092  
    SCHEMA_REGISTRY_HOST_NAME: schema-registry  

总结

核心结论:

  • Kafka Connect 定位:适用于标准化数据管道(如 MySQL → Kafka → Elasticsearch),但对复杂业务逻辑支持有限。
  • NestJS 集成建议:
    • 轻量级同步:直接使用 @nestjs/microservices(方案 1)
    • 大规模迁移:组合 Kafka Connect + NestJS 监控(方案 2)
  • 生产避坑指南:
    • 优先选择 Distributed 模式保障高可用。
    • 增量同步时严格验证 incrementing.column.name 避免数据丢失。
相关推荐
大数据追光猿2 小时前
【大数据生产问题】Flink CDC 同步 MySQL 到 StarRocks 时因字段新增导致任务失败?
大数据·数据库·mysql·flink
青石路2 小时前
用了MySQL的INSERT ON DUPLICATE KEY UPDATE,怎么还报唯一索引冲突错误
后端·sql·mysql
·云扬·2 小时前
MySQL大批量数据导入性能优化:从原理到实践
数据库·mysql·性能优化
追随者永远是胜利者2 小时前
mysql中三大日志文件的写入/刷盘时机
mysql·binlog·undolog·redolog
GeorgiaStar2 小时前
为什么Kafka不像MySQL与Redis那样做读写分离
kafka·系统架构
weixin_462446232 小时前
【原创实践】使用 Docker 在 MySQL 容器中批量导出所有数据库
数据库·mysql·docker
苹果醋33 小时前
24.记录Vue项目iview组件日期获取时间少一天
java·运维·spring boot·mysql·nginx
Wang's Blog3 小时前
Kafka: 集群部署与副本机制深度解析之从伪集群搭建到生产环境实践
分布式·kafka
HunterMichaelG3 小时前
【MySQL】KylinV10 ARM 服务器上编译MySQL 5.7 XtraBackup
mysql·arm·xtrabackup