从 PostgreSQL 实时同步
本文介绍如何通过 Flink CDC pipeline 将 PostgreSQL 的数据实时同步至 StarRocks。Pipeline 先复制每张表中已有的数据,然后在秒级内持续应用 PostgreSQL 中的每一条 INSERT、UPDATE 和 DELETE。Pipeline 会自动创建 StarRocks 表,因此无需单独同步库表结构。
导入操作需要目标表的 INSERT 权限。如果您的用户账号没有 INSERT 权限,请参考 GRANT 给用户赋权,语法为 GRANT INSERT ON TABLE <table_name> IN DATABASE <database_name> TO { ROLE <role_name> | USER <user_identity>}。
基本原理
Flink CDC pipeline 是一个 YAML 文件,包含 source(PostgreSQL)、sink(StarRocks),以及可选的 route 和 transform 规则。将该文件提交到 Flink 集群后,它会作为一个 Flink 作业运行:
- PostgreSQL source 为每张匹配的表创建快照,然后通过逻辑复制槽(replication slot)从 PostgreSQL 预写日志(WAL)中读取变更。
- StarRocks sink 为 StarRocks 中尚不存在的每张源表创建一张主键表,然后通过 Stream Load 导入数据。由于每张表都有主键,更新会覆盖已有的行,删除会移除对应的行。
数据投递语义为 at-least-once:发生故障后,部分变更可能会被再次写入,而主键表保证重复写入不会产生影响。
Pipeline 不会同步 PostgreSQL 的表结构变更。参见变更表结构。
准备工作
您需要:
- PostgreSQL 10 或更高版本。本文使用 PostgreSQL 内置的
pgoutput逻辑解码插件,无需安装服务端扩展。 - 一个 StarRocks 集群。
- 一个 Flink 1.20 集群,以及运行它所需的 Java 11 或 17。
- 每个 Flink TaskManager 都能通过网络访问 PostgreSQL 的端口(默认
5432),并按照连接 StarRocks 中的说明访问 StarRocks。 - 要同步的每张 PostgreSQL 表都有主键。StarRocks 会使用相同的主键创建目标表。
第一步:准备 PostgreSQL
请以 PostgreSQL 超级用 户或表的所有者身份执行以下步骤。示例同步的是 shop 数据库中 public schema 下的表。
-
开启逻辑复制。在
postgresql.conf中将wal_level设置为logical:wal_level = logical
# 每个运行中的 pipeline 使用一个复制槽和一个 WAL sender。
max_replication_slots = 4
max_wal_senders = 4修改
wal_level后需要重启 PostgreSQL。对于 Amazon RDS、Cloud SQL 等托管服务,请在实例的参数组中设置对应的参数(例如rds.logical_replication = 1)。重启后检查该设置:
SHOW wal_level;wal_level
-----------
logical -
为 Flink CDC 创建用户。该用户需要
REPLICATION属性以及表的读取权限:CREATE ROLE flink_cdc WITH LOGIN REPLICATION PASSWORD '<password>';
GRANT CONNECT ON DATABASE shop TO flink_cdc;
GRANT USAGE ON SCHEMA public TO flink_cdc;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO flink_cdc;如果
pg_hba.conf限制了复制连接,请允许该用户从 Flink TaskManager 所在主机连接。例如:# TYPE DATABASE USER ADDRESS METHOD
host shop flink_cdc 10.0.0.0/24 scram-sha-256
host replication flink_cdc 10.0.0.0/24 scram-sha-256 -
为要同步的表创建 publication。Publication 必须包含 pipeline 读取的所有表(即第四步中的
tables配置项):CREATE PUBLICATION flink_pub FOR TABLE public.orders, public.customers;提示请自行创建 publication。如果 publication 不存在,connector 会尝试执行
CREATE PUBLICATION ... FOR ALL TABLES,而只有超级用户才能执行该语句。对于其他用户,该语句会失败,Flink 会不断重试,直到报告的错误变成max_wal_senders,而不是缺少 publication。 -
将每张表的 replica identity 设置为
FULL,使 WAL 为每条 UPDATE 和 DELETE 记录完整的旧行:ALTER TABLE public.orders REPLICA IDENTITY FULL;
ALTER TABLE public.customers REPLICA IDENTITY FULL;请在启动 pipeline 之前完成此设置。使用默认的 replica identity 时,第一条 UPDATE 或 DELETE 会导致 Flink 作业因
NullPointerException失败,并且作业每次重启后都会在这条变更上再次失败。
第二步:准备 StarRocks
创建目标数据库以及 pipeline 使用的用户:
CREATE DATABASE shop;
CREATE USER flink_sink IDENTIFIED BY '<password>';
GRANT CREATE TABLE ON DATABASE shop TO USER flink_sink;
GRANT SELECT, INSERT, UPDATE, DELETE, ALTER ON ALL TABLES IN DATABASE shop TO USER flink_sink;
第三步:安装 Flink CDC
-
下载并启动 Flink 1.20。参见 Flink 文档中的 First steps。
-
在 Flink 配置文件
conf/config.yaml中添加以下配置以开启 Checkpoint,然后重启集群:execution.checkpointing.interval: 10sPostgreSQL source 会在 Checkpoint 完成时向 PostgreSQL 报告其在 WAL 中的位置。如果不开启 Checkpoint,复制槽会保留 pipeline 启动以来的所有 WAL 段,最终写满 PostgreSQL 的磁盘。
-
从 Flink CDC 下载页面下载与您的 Flink 版本匹配的 Flink CDC 版本,并解压。从 Flink CDC 3.6 开始,每个发布包只针对一个 Flink 版本构建,因此对于 Flink 1.20,请下载
flink-cdc-3.6.0-1.20-bin.tar.gz,而不是-2.2的包。tar -xzf flink-cdc-3.6.0-1.20-bin.tar.gz
cd flink-cdc-3.6.0-1.20 -
从 Maven Central 下载 PostgreSQL 和 StarRocks pipeline connector 到 Flink CDC 的
lib目录。请使用与 Flink CDC 发布包相同的版本:cd lib
wget https://repo1.maven.org/maven2/org/apache/flink/flink-cdc-pipeline-connector-postgres/3.6.0-1.20/flink-cdc-pipeline-connector-postgres-3.6.0-1.20.jar
wget https://repo1.maven.org/maven2/org/apache/flink/flink-cdc-pipeline-connector-starrocks/3.6.0-1.20/flink-cdc-pipeline-connector-starrocks-3.6.0-1.20.jar
cd ..
第四步:定义 pipeline
创建名为 postgres-to-starrocks.yaml 的文件:
source:
type: postgres
name: PostgreSQL source
hostname: <postgres_host>
port: 5432
username: flink_cdc
password: <password>
# 以逗号分隔的 <database>.<schema>.<table>,表名部分可以是正则表达式。
# 请列出与 publication 相同的表。
tables: shop.public.orders, shop.public.customers
# 要创建并使用的复制槽。只能包含小写字母、数字和下划线。
slot.name: flink_starrocks
decoding.plugin.name: pgoutput
debezium.publication.name: flink_pub
sink:
type: starrocks
name: StarRocks sink
# StarRocks 地址的设置方法,参见下文“连接 StarRocks”。
jdbc-url: jdbc:mysql://<fe_host>:9030
load-url: <fe_host>:8030
username: flink_sink
password: <password>
# 默认值为 300000(5 分钟)。较小的值可以让变更更快可见。
sink.buffer-flush.interval-ms: 5000
route:
# 将 public schema 下的每张表写入 StarRocks 数据库 shop。
- source-table: public.\.*
sink-table: shop.<>
replace-symbol: <>
pipeline:
name: PostgreSQL to StarRocks
parallelism: 1
请注意以下配置:
tables必须与 publication 一致。快照会复制tables选中的所有表,但 PostgreSQL 只会为 publication 中的表推送变更。不在 publication 中的表只会被复制一次,之后不再更新,作业也不会报告任何错误。tables使用<database>.<schema>.<table>的格式指定表。但在 pipeline 内部,PostgreSQL 表只用<schema>.<table>标识,因此route和transform规则应匹配public.orders,而不是shop.public.orders。- 如果没有
route配置,sink 会将每张表写入以 PostgreSQL schema 命名的 StarRocks 数据库,因此public下的表会写入名为public的数据库。 sink.buffer-flush.interval-ms的默认值为 5 分钟。使用默认值时,新启动的 pipeline 在几分钟内看起来没有任何动作。- 如需为 sink 创建的表设置属性,请在
sink部分添加table.create.properties.<property>,例如table.create.properties.replication_num: 1。
有关 source 和 sink 的所有配置项,请参见 Flink CDC 的 Postgres connector 和 StarRocks connector 参考文档。
连接 StarRocks
将 StarRocks 连接配置项设置为 FE 的地址:
jdbc-url:jdbc:mysql://<fe_host>:<fe_query_port>。查询端口默认为9030。load-url:<fe_host>:<fe_http_port>。HTTP 端口默认为8030。
<fe_host> 请使用在 FE 重启或被替换后保持不变的地址,例如 DNS 域名或 FE 前端的负载均衡器,而不是某个 FE 的 IP 地址。如果该地址不再指向 FE,Flink 作业将无法继续导入数据。
Flink TaskManager 必须能够访问上述 FE 端口,以及每个 BE 或 CN 的 HTTP 端口(默认 8040),因为 FE 会将每个导入请求重定向到某个 BE 或 CN。