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

相关推荐
恋喵大鲤鱼2 天前
分布式消息投递模型快速上手
消息队列·投递模型
少许极端4 天前
消息队列5-RabbitMQ的高级特性和MQ的应用问题与解决方案-事务、消息分发的应用、幂等性保证、顺序性保证、消息积压的解决
分布式·消息队列·rabbitmq
却话巴山夜雨时i5 天前
互联网大厂Java面试场景:从基础到微服务的循序渐进提问
java·数据库·spring·微服务·面试·消息队列·技术栈
__土块__5 天前
一次支付清结算系统线程池故障复盘:从任务积压到异步解耦的架构演进
java·消息队列·rocketmq·线程池·支付系统·故障复盘·异步架构
少许极端7 天前
消息队列4-RabbitMQ的高级特性-TTL机制、死信队列、延迟队列
分布式·消息队列·rabbitmq
014-code7 天前
RabbitMQ 生产端可靠投递(confirm、return、重试)
分布式·消息队列·rabbitmq
014-code7 天前
RabbitMQ 消费端幂等实战(重复消息、去重、重放怎么处理)
分布式·消息队列·rabbitmq
代码AC不AC9 天前
【Linux】System V 通信方式
linux·消息队列·共享内存·信号量·system v
AutoMQ9 天前
360 如何用 AutoMQ 解决千亿级 Kafka 冷读难题
kafka·消息队列·云计算
indexsunny10 天前
互联网大厂Java面试实战:从Spring Boot到微服务的技术问答解析
java·spring boot·redis·微服务·消息队列·电商