前言
在微服务架构和数据驱动的时代,数据同步是企业最常见也最棘手的工程挑战之一。传统做法往往需要编写大量的 ETL 代码、维护定时任务、处理各种异常重试逻辑。Apache Pulsar 内置的 Pulsar IO 框架提供了一种"零代码"的方式------仅通过编写 YAML/JSON 配置文件并执行一条 CLI 命令,即可完成复杂的数据同步链路搭建。
本文将围绕两大核心场景展开:
- 数据库 Binlog 变更订阅 ------ 实时捕获数据库增删改事件
- 异构数据源同步 ------ 跨数据库、跨存储引擎的数据流转
一、Pulsar IO 架构概览
Pulsar IO 是 Pulsar 原生的 Connector 框架,由 Source (数据源连接器)和 Sink(数据目标连接器)两部分组成:
┌─────────────┐ ┌───────────────────┐ ┌──────────────┐
│ 外部数据源 │────▶│ Source Connector │────▶│ Pulsar Topic │
│ (MySQL, PG...) │ │ (Debezium, Canal) │ │ │
└─────────────┘ └───────────────────┘ └──────┬───────┘
│
▼
┌───────────────────┐ ┌──────────────┐
│ Sink Connector │────▶│ 外部目标 │
│ (ES, JDBC, Redis) │ │ (ES, PG, ...) │
└───────────────────┘ └──────────────┘
核心优势
- 零代码:只需编写配置文件,不需要写任何 Java/Python 代码
- 内置 30+ 连接器:覆盖 MySQL、PostgreSQL、MongoDB、Elasticsearch、Kafka、Redis、HDFS 等主流系统
- Exactly-Once 语义:配合 Pulsar 事务,可实现端到端精确一次语义
- 弹性伸缩 :通过
parallelism参数调整并发度,由 Pulsar Functions Worker 自动调度 - 统一管理 :通过
pulsar-adminCLI 或 REST API 统一创建、监控、更新、停止连接器
内置连接器一览
|----------------|------------------------------------------------------------------------------------------|
| 类型 | 连接器 |
| CDC Source | Debezium MySQL、Debezium PostgreSQL、Debezium MongoDB、Debezium Oracle、Debezium MSSQL、Canal |
| 消息队列 | Kafka、RabbitMQ、NSQ |
| 数据库 Sink | JDBC PostgreSQL、JDBC MariaDB、JDBC ClickHouse、MongoDB、Cassandra、HBase |
| 搜索引擎 | Elasticsearch / OpenSearch、Solr |
| 缓存 | Redis |
| 大数据存储 | HDFS、Alluxio |
| 云服务 | AWS Kinesis、DynamoDB、Azure Data Explorer |
二、场景一:数据库 Binlog 变更订阅
2.1 业务场景
实时感知数据库变更是许多业务的基础需求:
- 缓存失效:数据库表发生变更时,立即通知下游清除或更新 Redis 缓存
- 搜索索引更新:商品表变更后实时同步到 Elasticsearch,保证搜索结果实时性
- 审计日志:记录每一条数据变更的完整历史,用于合规审计
- 跨系统事件驱动:订单状态变更后触发物流、支付、通知等下游服务
2.2 方案一:Debezium MySQL Source(推荐)
Debezium 是业界最成熟的 CDC(Change Data Capture)框架。Pulsar 原生集成了 Debezium,支持 MySQL、PostgreSQL、MongoDB、Oracle、MSSQL 五大数据库。
第一步:开启 MySQL Binlog
确保 MySQL 开启了 ROW 模式的 binlog:
-- my.cnf 配置
[mysqld]
server-id = 1
log_bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL
创建专用的 Debezium 账户并授权:
CREATE USER 'debezium'@'%' IDENTIFIED BY 'dbz_password';
GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'debezium'@'%';
FLUSH PRIVILEGES;
第二步:编写 Source 配置文件
创建 debezium-mysql-source.yaml:
tenant: "public"
namespace: "default"
name: "debezium-mysql-source"
topicName: "persistent://public/default/debezium-mysql-topic"
archive: "connectors/pulsar-io-debezium-mysql.nar"
parallelism: 1
configs:
database.hostname: "192.168.1.100"
database.port: "3306"
database.user: "debezium"
database.password: "dbz_password"
database.server.id: "184054"
database.server.name: "bizdb"
# 订阅指定数据库(多个用逗号分隔)
database.whitelist: "order_db,user_db"
# Schema 变更历史存储在 Pulsar Topic 中
database.history.pulsar.topic: "persistent://public/default/mysql-schema-history"
database.history.pulsar.service.url: "pulsar://127.0.0.1:6650"
# Offset 存储(记录消费位点,重启后断点续传)
offset.storage.topic: "persistent://public/default/mysql-offset-topic"
第三步:一条命令启动
bin/pulsar-admin sources create \
--source-config-file debezium-mysql-source.yaml
验证运行状态:
bin/pulsar-admin sources status --name debezium-mysql-source
第四步:消费 Binlog 事件
此时,对 order_db 和 user_db 中任何表的增删改操作都会实时写入 Pulsar Topic。事件以 JSON 格式存储,包含完整的 before/after 数据:
{
"schema": { ... },
"payload": {
"before": null,
"after": {
"id": 1001,
"user_id": 10086,
"amount": 299.00,
"status": "PAID",
"created_at": 1709856000000
},
"source": {
"version": "1.9.7.Final",
"connector": "mysql",
"name": "bizdb",
"ts_ms": 1709856001000,
"db": "order_db",
"table": "orders",
"server_id": 1,
"file": "mysql-bin.000003",
"pos": 12345
},
"op": "c",
"ts_ms": 1709856001234
}
}
其中 op 字段表示操作类型:c = INSERT、u = UPDATE、d = DELETE、r = READ(快照)。
2.3 方案二:Canal Source
Canal 是阿里巴巴开源的 MySQL Binlog 增量订阅组件,如果团队已有 Canal 基础设施,Pulsar 同样提供了原生 Canal Source 连接器。
创建 canal-mysql-source.yaml:
tenant: "public"
namespace: "default"
name: "canal-mysql-source"
topicName: "persistent://public/default/canal-mysql-topic"
archive: "connectors/pulsar-io-canal.nar"
parallelism: 1
configs:
zkServers: "192.168.1.100:2181"
batchSize: "5120"
destination: "example"
username: ""
password: ""
cluster: false
singleHostname: "192.168.1.100"
singlePort: "11111"
bin/pulsar-admin sources create \
--source-config-file canal-mysql-source.yaml
2.4 PostgreSQL CDC
Debezium 同样支持 PostgreSQL 的逻辑复制(Logical Replication)。只需开启 wal_level = logical,然后部署 Debezium PostgreSQL Source:
tenant: "public"
namespace: "default"
name: "debezium-postgres-source"
topicName: "persistent://public/default/debezium-pg-topic"
archive: "connectors/pulsar-io-debezium-postgres.nar"
parallelism: 1
configs:
database.hostname: "192.168.1.101"
database.port: "5432"
database.user: "postgres"
database.password: "postgres"
database.dbname: "mydb"
database.server.name: "pgserver1"
schema.whitelist: "public"
database.history.pulsar.service.url: "pulsar://127.0.0.1:6650"
bin/pulsar-admin sources create \
--source-config-file debezium-postgres-source.yaml
三、场景二:异构数据源同步
3.1 业务场景
企业中最常见的异构同步需求包括:
- MySQL → Elasticsearch:将业务数据实时同步到搜索引擎,支撑全文检索和复杂查询
- MySQL → PostgreSQL / ClickHouse:将 OLTP 数据同步到 OLAP 数据库进行分析
- MySQL → Redis:将热点数据实时同步到缓存层
- MySQL → MongoDB:结构化数据同步到文档型数据库
Pulsar IO 的 Source + Sink 组合可以零代码打通这些链路。核心思路是:
MySQL ──[Debezium Source]──▶ Pulsar Topic ──[Sink Connector]──▶ 目标系统
3.2 实战:MySQL → Elasticsearch 实时同步
这是最高频的异构同步场景。用户在 MySQL 中更新商品信息,Elasticsearch 中的搜索索引同步刷新。
架构示意
┌─────────┐ binlog ┌───────────────┐ message ┌──────────────┐ ┌───────────────┐
│ MySQL │─────────▶│ Debezium MySQL │─────────▶│ Pulsar Topic │─────▶│ ES Sink │
│ (OLTP) │ │ Source │ │ │ │ Connector │
└─────────┘ └───────────────┘ └──────────────┘ └───────┬───────┘
│
▼
┌───────────────┐
│ Elasticsearch │
│ (搜索/分析) │
└───────────────┘
第一步:部署 Debezium MySQL Source(同上)
复用前面 2.2 节的配置即可。
第二步:部署 Elasticsearch Sink
创建 es-sink.yaml:
tenant: "public"
namespace: "default"
name: "es-sink"
inputs:
- "persistent://public/default/debezium-mysql-topic"
archive: "connectors/pulsar-io-elastic-search.nar"
parallelism: 1
configs:
elasticSearchUrl: "http://192.168.1.200:9200"
indexName: "products"
schemaEnable: "true"
createIndexIfNeeded: "true"
username: "elastic"
password: "changeme"
primaryFields: "id"
bin/pulsar-admin sinks create \
--sink-config-file es-sink.yaml
验证状态:
bin/pulsar-admin sinks status --name es-sink
完成!现在 MySQL products 表的每一次变更都会实时同步到 Elasticsearch 的 products 索引。
3.3 实战:MySQL → PostgreSQL 跨库同步
将 MySQL 中的订单数据同步到 PostgreSQL 做 OLAP 分析。
第一步:Source 端(复用 Debezium MySQL Source)
第二步:部署 JDBC PostgreSQL Sink
在 PostgreSQL 中提前创建目标表:
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10, 2),
status VARCHAR(32),
created_at TIMESTAMP
);
创建 jdbc-pg-sink.yaml:
tenant: "public"
namespace: "default"
name: "jdbc-pg-sink"
inputs:
- "persistent://public/default/debezium-mysql-topic"
archive: "connectors/pulsar-io-jdbc-postgres.nar"
parallelism: 1
configs:
jdbcUrl: "jdbc:postgresql://192.168.1.102:5432/analytics"
userName: "postgres"
password: "postgres"
tableName: "orders"
insertMode: "UPSERT"
nullValueAction: "DELETE"
batchSize: 200
timeoutMs: 500
useTransactions: true
useJdbcBatch: true
key: "id"
nonKey: "user_id,amount,status,created_at"
bin/pulsar-admin sinks create \
--sink-config-file jdbc-pg-sink.yaml
关键配置说明:
|---------------------------|---------------------------------------------|
| 配置项 | 说明 |
| insertMode: UPSERT | 存在则更新,不存在则插入,保证幂等性 |
| nullValueAction: DELETE | 收到 null 值消息时执行删除操作(对应 Debezium 的 DELETE 事件) |
| key: "id" | 主键字段,用于 UPSERT 和 DELETE 的 WHERE 条件 |
| nonKey | 非主键字段,用于 UPDATE SET 子句 |
| useJdbcBatch: true | 启用 JDBC 批量写入,显著提升吞吐量 |
3.4 实战:MySQL → Redis 缓存同步
创建 redis-sink.yaml:
tenant: "public"
namespace: "default"
name: "redis-sink"
inputs:
- "persistent://public/default/debezium-mysql-topic"
archive: "connectors/pulsar-io-redis.nar"
parallelism: 1
configs:
redisHosts: "192.168.1.103:6379"
redisPassword: "your_password"
redisDatabase: "0"
clientMode: "Standalone"
operationTimeout: "2000"
batchSize: "100"
batchTimeMs: "1000"
connectTimeout: "3000"
bin/pulsar-admin sinks create \
--sink-config-file redis-sink.yaml
3.5 一个 Source 多个 Sink:扇出模式
Pulsar IO 最强大的能力之一是一个 Source 可以驱动多个 Sink。因为所有变更数据都存储在 Pulsar Topic 中,不同的 Sink 以各自独立的 Subscription 消费同一个 Topic,互不干扰:
┌──[ES Sink]──────────▶ Elasticsearch
│
MySQL ──[Debezium Source]──▶ Pulsar Topic ──[JDBC Sink]─────────▶ PostgreSQL
│
├──[Redis Sink]────────▶ Redis
│
└──[Kafka Sink]────────▶ Kafka (Legacy)
这种扇出模式的好处:
- 对 MySQL 只抽取一次,不增加源数据库压力
- 各 Sink 独立消费,一个 Sink 故障不影响其他
- Pulsar Topic 天然持久化,任何 Sink 宕机恢复后从断点继续消费
- 可随时新增 Sink,无需修改 Source 配置
四、运维与监控
4.1 常用管理命令
# 查看所有正在运行的 Source 连接器
bin/pulsar-admin sources list --tenant public --namespace default
# 查看所有正在运行的 Sink 连接器
bin/pulsar-admin sinks list --tenant public --namespace default
# 查看连接器详细状态(含处理消息数、错误数等)
bin/pulsar-admin sources status --name debezium-mysql-source
bin/pulsar-admin sinks status --name es-sink
# 更新连接器配置(热更新,无需重建)
bin/pulsar-admin sinks update --sink-config-file es-sink-v2.yaml
# 停止 / 重启连接器
bin/pulsar-admin sinks stop --name es-sink
bin/pulsar-admin sinks restart --name es-sink
# 查看内置可用连接器列表
bin/pulsar-admin sources available-sources
bin/pulsar-admin sinks available-sinks
4.2 本地调试
开发阶段可使用 localrun 命令在本地运行连接器,无需部署完整的 Pulsar 集群:
bin/pulsar-admin sources localrun \
--source-config-file debezium-mysql-source.yaml
bin/pulsar-admin sinks localrun \
--sink-config-file es-sink.yaml
4.3 处理保证
Pulsar IO 支持三种消息处理保证级别,通过 --processing-guarantees 参数指定:
|--------------------|----------|---------------------------|
| 级别 | 说明 | 适用场景 |
| ATLEAST_ONCE | 至少一次(默认) | 大多数场景,配合幂等 Sink(如 UPSERT) |
| ATMOST_ONCE | 至多一次 | 可容忍丢失的监控日志等 |
| EFFECTIVELY_ONCE | 精确一次 | 金融交易等不能重复/丢失的场景 |
五、最佳实践
5.1 Topic 设计
- 按表拆分 Topic:为每张被监控的表分配独立的 Topic(Debezium 默认行为),方便下游按需订阅
- 使用持久化 Topic :确保 Binlog 事件不丢失,使用
persistent://前缀 - 合理设置 Retention:根据业务需要配置 Topic 的消息保留策略
5.2 性能调优
- parallelism:增大 Source/Sink 的并发度以提高吞吐量
- batchSize:在 JDBC Sink 中适当增大批量写入大小(如 500-1000)
- useJdbcBatch:JDBC Sink 必须开启以获得最佳写入性能
- Elasticsearch 批量写入:ES Sink 内部已自动使用 Bulk API
5.3 高可用
- Pulsar IO 连接器由 Functions Worker 管理,Worker 集群本身具备高可用
- 连接器实例故障后会自动重新调度到其他 Worker 节点
- 通过
offset.storage.topic持久化消费位点,重启后断点续传
六、总结
|-------------|--------------------------|
| 传统方案 | Pulsar IO 方案 |
| 编写 ETL 代码 | 编写 YAML 配置文件 |
| 维护定时调度任务 | 实时流式同步 |
| 自行处理断点续传 | 框架自动管理 Offset |
| 点对点耦合 | Source → Topic → Sink 解耦 |
| 每新增一个目标需改代码 | 新增一个 Sink 配置文件即可 |
| 单独搭建监控 | pulsar-admin 统一管理 |
通过 Pulsar IO,企业可以用零代码的方式快速搭建数据同步管线。无论是数据库 Binlog 变更订阅还是异构数据源之间的实时同步,都只需要三步:
- 编写一个 YAML 配置文件
- 执行一条
pulsar-admin命令 - 验证运行状态
Pulsar 作为中间的消息总线,天然解耦了数据源与目标系统,让数据流转变得简单、可靠、可观测。