Pulsar IO 应用场景及案例

前言

在微服务架构和数据驱动的时代,数据同步是企业最常见也最棘手的工程挑战之一。传统做法往往需要编写大量的 ETL 代码、维护定时任务、处理各种异常重试逻辑。Apache Pulsar 内置的 Pulsar IO 框架提供了一种"零代码"的方式------仅通过编写 YAML/JSON 配置文件并执行一条 CLI 命令,即可完成复杂的数据同步链路搭建。

本文将围绕两大核心场景展开:

  1. 数据库 Binlog 变更订阅 ------ 实时捕获数据库增删改事件
  2. 异构数据源同步 ------ 跨数据库、跨存储引擎的数据流转

一、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-admin CLI 或 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_dbuser_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 变更订阅还是异构数据源之间的实时同步,都只需要三步:

  1. 编写一个 YAML 配置文件
  2. 执行一条 pulsar-admin命令
  3. 验证运行状态

Pulsar 作为中间的消息总线,天然解耦了数据源与目标系统,让数据流转变得简单、可靠、可观测。

相关推荐
014-code2 天前
Kafka + Spring Boot 实战入门
java·spring boot·kafka·消息队列
Chan169 天前
从生产到消费:Kafka 核心原理与实战指南
java·spring boot·分布式·spring·java-ee·kafka·消息队列
茶杯梦轩15 天前
从零起步学习RabbitMQ || 第二章:RabbitMQ 深入理解概念 Producer、Consumer、Exchange、Queue 与企业实战案例
服务器·后端·消息队列
初次攀爬者17 天前
Kafka 基础介绍
spring boot·kafka·消息队列
初次攀爬者17 天前
RocketMQ 消息可靠性保障与堆积处理
后端·消息队列·rocketmq
初次攀爬者18 天前
RocketMQ 集群介绍
后端·消息队列·rocketmq
初次攀爬者18 天前
RocketMQ 基础学习
后端·消息队列·rocketmq
初次攀爬者19 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
DemonAvenger21 天前
Kafka性能调优:从参数配置到硬件选择的全方位指南
性能优化·kafka·消息队列