【Kafka源码解读和使用指南】第71篇:Kafka Connect实战——10分钟搭建MySQL到Elasticsearch数据管道

上一篇【第70篇】Kafka多数据中心高可用——跨数据中心的Kafka高可用
下一篇【第72篇】Kafka Connect深度解析——Connector是如何工作的


摘要

Kafka Connect是Kafka生态中负责数据集成的主力工具。它把"从A系统读、写到B系统"这个ETL场景标准化成了可插拔的Connector架构。很多人知道要用Connect,但第一次配置时总被各种参数搞懵。

本文将手把手带你用Kafka Connect搭建一条MySQL → Kafka → Elasticsearch的实时数据管道。从Connect集群启动、JDBC Source Connector配置、ES Sink Connector配置,到全链路验证,每一步都有可运行的命令和配置。10分钟后,你就能看到MySQL的数据实时出现在Elasticsearch里。


一、Kafka Connect 架构速览

先搞清楚Connect的本质:

【Kafka Connect 架构图】

  ┌─────────────────────────────────────────────────┐
  │              Kafka Connect Cluster                 │
  │                                                     │
  │  ┌──────────────┐  ┌──────────────┐       │
  │  │  Worker 1   │  │  Worker 2   │       │
  │  │  (Standalone │  │  (Distributed │       │
  │  │   /Distributed)│  │   Mode)      │       │
  │  └──────┬───────┘  └──────┬───────┘       │
  │         │                      │                  │
  │         ▼                      ▼                  │
  │  ┌──────────────────────────────────┐     │
  │  │         Kafka Topic                 │     │
  │  │  mysql-orders (3 partitions)       │     │
  │  └──────────────────┬───────────────┘     │
  │                         │                            │
  │                         ▼                            │
  │  ┌──────────────┐  ┌──────────────┐         │
  │  │  ES Sink    │  │  ES Sink    │         │
  │  │  Connector   │  │  Connector   │         │
  │  │  (Task×3)   │  │  (Task×3)   │         │
  │  └──────────────┘  └──────────────┘         │
  └─────────────────────────────────────────────────┘
           │
           ▼
  ┌──────────────────┐
  │   Elasticsearch  │
  │   Index: orders   │
  └──────────────────┘

核心概念

概念含义类比
Connector数据管道的定义(从哪来、到哪去)蓝图
TaskConnector的实际执行单元(并行度)工人
Worker运行Connector/Task的进程工地
Source Connector从外部系统读数据写入Kafka进口
Sink Connector从Kafka读数据写入外部系统出口

二、启动Connect集群(Distributed模式)

2.1 为什么选Distributed模式

【Standalone vs Distributed】

  Standalone(单机):
  ┌────────────────────┐
  │  所有Connector跑在一个进程  │
  │  → 挂了全挂(无HA)          │
  │  → 无法横向扩展             │
  └────────────────────┘

  Distributed(分布式)★推荐:
  ┌────────────────────┐
  │  多个Worker组成集群          │
  │  → 自动负载均衡              │
  │  → Worker挂了自动迁移Task    │
  │  → 支持Rest API管理         │
  └────────────────────┘

2.2 Worker配置文件

# connect-distributed.properties
# ===== 核心配置 =====

# 集群唯一名称(同一集群的Worker要用同一个)
group.id=connect-cluster

# REST API监听地址
rest.host.name=0.0.0.0
rest.port=8083

# Kafka集群地址(Connect用自己的Kafka存offset和状态)
bootstrap.servers=localhost:9092

# 内部Topic配置(Connect自动创建,不要手动建)
offset.storage.topic=connect-offsets
offset.storage.replication.factor=3
offset.storage.partitions=25

config.storage.topic=connect-configs
config.storage.replication.factor=3

status.storage.topic=connect-status
status.storage.replication.factor=3

# KEY/VALUE 转换器(消息格式)
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter
key.converter.schemas.enable=false
value.converter.schemas.enable=false

# 并行度
tasks.max=4

2.3 启动Worker

# 启动第一个Worker
export CLASSPATH=/path/to/connector-plugins/*

bin/connect-distributed.sh \
  config/connect-distributed.properties &

# 等待启动完成(看到 "Started" 日志)
# REST API可用:http://localhost:8083

# 验证集群状态
curl http://localhost:8083/ | jq .

# 预期输出:
# {
#   "version": "3.6.0",
#   "commit": "abc123",
#   "kafka_cluster_id": "xyz789"
# }

三、部署JDBC Source Connector(MySQL → Kafka)

3.1 下载JDBC Connector插件

# Confluent官方的JDBC Connector
# 下载地址:https://www.confluent.io/hub/confluentinc/kafka-connect-jdbc

# 解压到Connect的插件目录
mkdir -p /opt/kafka/plugins
tar -xzf confluentinc-kafka-connect-jdbc-*.tar.gz \
  -C /opt/kafka/plugins/

# 把MySQL驱动也放进去
cp mysql-connector-j-8.0.*.jar /opt/kafka/plugins/

# 重启所有Worker(加载新插件)
# 或者热加载(如果配置了plugin.path)

3.2 创建JDBC Source Connector

# 创建MySQL Source Connector
curl -X POST http://localhost:8083/connectors \
  -H "Content-Type: application/json" \
  -d '{
    "name": "mysql-orders-source",
    "config": {
      "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
      "tasks.max": "2",
      
      # === 数据库连接 ===
      "connection.url": "jdbc:mysql://localhost:3306/orders_db?useSSL=false",
      "connection.user": "kafka_user",
      "connection.password": "kafka_pass",
      
      # === 要同步的表 ===
      "table.whitelist": "orders,order_items",
      "mode": "timestamp+incrementing",
      "timestamp.column.name": "updated_at",
      "incrementing.column.name": "id",
      
      # === Topic配置 ===
      "topic.prefix": "mysql-",
      
      # === 轮询间隔 ===
      "poll.interval.ms": "5000",
      
      # === 批量大小 ===
      "batch.max.rows": "1000"
    }
  }' | jq .

3.3 配置参数详解

【JDBC Source 关键参数】

  ┌──────────────────────────────────────────────────────┐
  │ 参数                         │ 说明                     │
  ├─────────────────────────┼─────────────────────┤
  │ mode                        │ 增量检测模式               │
  │  • "bulk"                  │ 全表扫描(首次用)         │
  │  • "incrementing"           │ 按自增ID拉取             │
  │  • "timestamp"              │ 按时间戳列拉取           │
  │  • "timestamp+incrementing"  │ ★推荐:两者结合          │
  ├─────────────────────────┼─────────────────────┤
  │ topic.prefix               │ Topic名称前缀               │
  │   → 实际Topic: mysql-orders                             │
  ├──────────────────────────────────────────────────────┤
  │ poll.interval.ms           │ 每次轮询间隔(毫秒)       │
  │   → 5秒检查一次新数据                    │
  ├──────────────────────────────────────────────────────┤
  │ timestamp.initial          │ 首次启动时如何处理已有数据   │
  │  • "latest"                │ 跳过历史数据(只同步新)   │
  │  • "earliest"              │ 同步全部历史数据 ★        │
  └──────────────────────────────────────────────────────┘

3.4 验证Source Connector

# 查看Connector状态
curl http://localhost:8083/connectors/mysql-orders-source/status | jq .

# 预期输出:
# {
#   "name": "mysql-orders-source",
#   "connector": { "state": "RUNNING", "worker_id": "..." },
#   "tasks": [
#     { "id": 0, "state": "RUNNING", "worker_id": "..." },
#     { "id": 1, "state": "RUNNING", "worker_id": "..." }
#   ],
#   "type": "source"
# }

# 检查Topic是否已创建
bin/kafka-topics.sh --bootstrap-server localhost:9092 \
  --list | grep mysql-

# 预期看到:mysql-orders, mysql-order_items

# 消费数据验证
bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic mysql-orders \
  --from-beginning \
  --property print.key=true

四、部署ES Sink Connector(Kafka → Elasticsearch)

4.1 下载ES Connector插件

# Confluent官方的Elasticsearch Connector
# 下载地址:https://www.confluent.io/hub/confluentinc/kafka-connect-elasticsearch

tar -xzf confluentinc-kafka-connect-elasticsearch-*.tar.gz \
  -C /opt/kafka/plugins/

# 重启Worker加载插件

4.2 创建ES Sink Connector

curl -X POST http://localhost:8083/connectors \
  -H "Content-Type: application/json" \
  -d '{
    "name": "es-orders-sink",
    "config": {
      "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
      "tasks.max": "2",
      
      # === Kafka侧配置 ===
      "topics": "mysql-orders",
      "value.conversion.schemas.enable": "false",
      
      # === ES侧配置 ===
      "connection.url": "http://localhost:9200",
      "type.name": "_doc",
      "key.ignore": "true",
      
      # === 写入行为 ===
      "behavior.on.malformation": "IGNORE",
      "max.buffered.records": "10000",
      "batch.size": "2000",
      "linger.ms": "500",
      
      # === ID映射 ===
      "key.ignore": "true",
      "schemas.enable": "false"
    }
  }' | jq .

4.3 Sink Connector参数详解

【ES Sink 关键参数】

  ┌──────────────────────────────────────────────────────┐
  │ 参数                    │ 说明                    │
  ├────────────────────────┼──────────────────────┤
  │ connection.url          │ ES集群地址             │
  │                          │ 支持多个(逗号分隔)    │
  ├────────────────────────┼──────────────────────┤
  │ type.name              │ ES的type(7.x后固定    │
  │                          │ 为_doc)                │
  ├────────────────────────┼──────────────────────┤
  │ key.ignore             │ 是否忽略消息的Key       │
  │ • true                  │ 用消息内容生成ES _id   │
  │ • false                 │ 用Kafka消息Key作为     │
  │                          │ ES _id                 │
  ├────────────────────────┼──────────────────────┤
  │ topics.regex           │ 用正则匹配多个Topic     │
  │                          │ 替代单个topics配置     │
  ├────────────────────────┼──────────────────────┤
  │ max.buffered.records  │ 最大缓冲记录数         │
  │                          │ 调大可提升吞吐         │
  └──────────────────────────────────────────────────────┘

五、全链路验证

5.1 端到端测试

-- Step 1: 在MySQL中插入一条测试数据
USE orders_db;
INSERT INTO orders (id, user_id, amount, status, created_at, updated_at)
VALUES (1001, 501, 99.9, 'PAYED', NOW(), NOW());

-- 确认数据已写入
SELECT * FROM orders WHERE id = 1001;
# Step 2: 检查Kafka Topic中是否出现这条消息
bin/kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic mysql-orders \
  --from-beginning \
  --max-messages 1

# 预期输出(JSON格式):
# {"schema":{...},"payload":{"id":1001,"user_id":501,...}}
# Step 3: 检查Elasticsearch中是否出现这条文档
curl -X GET "http://localhost:9200/orders/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "query": { "match": { "id": 1001 }}
  }'

# 预期输出包含:
# {
#   "hits": {
#     "total": { "value": 1 },
#     "hits": [
#       { "_index": "orders", "_id": "...", "_source": { "id": 1001, ... }}
#     ]
#   }
# }

5.2 延迟测量

# 测量端到端延迟(MySQL → Kafka → ES)

# 在MySQL中写入带时间戳的记录
mysql> INSERT INTO orders (id, user_id, amount, created_at, updated_at)
    -> VALUES (2001, 601, 50.0, NOW(3), NOW(3));

# 记录写入时间
MYSQL_TIME=$(date +%s%3N)

# 轮询ES直到出现这条记录
while true; do
  RESULT=$(curl -s -X GET "http://localhost:9200/orders/_search" \
    -H "Content-Type: application/json" \
    -d "{\"query\":{\"match\":{\"id\":2001}}}")
  
  if echo "$RESULT" | grep -q "\"found\":true"; then
    ES_TIME=$(date +%s%3N)
    LATENCY=$((ES_TIME - MYSQL_TIME))
    echo "端到端延迟: ${LATENCY}ms"
    break
  fi
  sleep 0.5
done

# 典型延迟:500ms ~ 3000ms(取决于 poll.interval.ms)

六、生产环境部署要点

6.1 高可用配置

# connect-distributed.properties(生产环境增强)

# 增加内部Topic的副本数
offset.storage.replication.factor=3
config.storage.replication.factor=3
status.storage.replication.factor=3

# 启用Connector的自动重启
# Connect会监控Task状态,失败时自动重启
status.storage.replication.factor=3

# REST API绑定内网地址(不要暴露到公网)
rest.host.name=192.168.1.50

6.2 监控Connect集群

# 查看所有Connector的状态
curl http://localhost:8083/connectors?expand=status | jq .

# 查看Worker集群信息
curl http://localhost:8083/workers | jq .

# 查看Connector的tasks分布
curl http://localhost:8083/connectors/mysql-orders-source/tasks | jq .
# Prometheus JMX Exporter配置(监控Connect)
rules:
  - pattern: 'kafka.connect<type=connector-metrics,    
                connector=(.*)><>RecordReadTotal'
    name: kafka_connect_records_read_total
    labels:
      connector: '$1'
      
  - pattern: 'kafka.connect<type=connector-metrics,
                connector=(.*)><>RecordWriteTotal'
    name: kafka_connect_records_write_total
    labels:
      connector: '$1'
      
  - pattern: 'kafka.connect<type=task-metrics,
                connector=(.*), task=(.*)><>RecordErrorsTotal'
    name: kafka_connect_record_errors_total
    labels:
      connector: '$1'
      task: '$2'

本篇小结

今天我们手把手搭建了一条MySQL → Kafka → Elasticsearch的实时数据管道:

  1. Connect架构:Worker集群 + Connector(Source/Sink)+ Task(并行执行单元)
  2. 启动集群:用Distributed模式,配置内部Topic(offset/config/status)
  3. JDBC Source:配置mode=timestamp+incrementing实现增量同步
  4. ES Sink:配置connection.urlkey.ignore完成写入
  5. 全链路验证:插入→Kafka消费验证→ES查询验证,三步确认数据流转正常

核心要点:Connector的配置80%的时间花在"上下游系统的认证授权"上,先把数据库/ES的账号权限配好,再调试Connector参数。

下一篇,我们将深入Connect的内部机制——Connector是怎么被加载的、Task是怎么分配到Worker的、offset是怎么管理的,用源码视角彻底理解Connect的工作原理。


上一篇【第70篇】Kafka多数据中心高可用——跨数据中心的Kafka高可用
下一篇【第72篇】Kafka Connect深度解析——Connector是如何工作的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值