一、PostgreSQL 数据库核心配置
1. 启用逻辑解码(Logical Decoding)
PostgreSQL CDC 依赖逻辑解码功能获取增量变更,需在 postgresql.conf
中启用以下配置:
ini
# 启用逻辑解码
wal_level = logical
# 保留日志天数(根据业务需求调整)
max_wal_senders = 10
wal_keep_segments = 32 # 每个段16MB,32段约512MB
修改后重启PostgreSQL服务使配置生效。
2. 创建逻辑解码槽(Replication Slot)
逻辑解码槽用于存储CDC读取位置,每个Flink作业需创建独立槽(避免冲突):
sql
-- 以postgres用户连接数据库
CREATE USER flinkuser WITH PASSWORD 'flinkpw';
GRANT CONNECT ON DATABASE postgres TO flinkuser;
-- 创建解码槽(使用decoderbufs插件,适用于9.4+版本)
-- 注意:槽名需唯一,建议按表或作业命名
SELECT pg_create_logical_replication_slot('flink_slot', 'decoderbufs');
-- 查看所有解码槽
SELECT * FROM pg_replication_slots;
3. 授予用户权限
sql
-- 授予基本权限
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO flinkuser;
GRANT USAGE ON SCHEMA public TO flinkuser;
GRANT CREATE ON SCHEMA public TO flinkuser;
-- 授予复制权限(关键:读取WAL日志)
GRANT REPLICATION TO flinkuser;
-- 刷新权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO flinkuser;
二、Flink 环境集成配置
1. 添加Maven依赖
xml
<dependency>
<groupId>com.ververica</groupId>
<artifactId>flink-sql-connector-postgres-cdc</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
2. SQL Client部署
- 下载JAR包:flink-sql-connector-postgres-cdc-3.0.1.jar
- 放入
$FLINK_HOME/lib/
目录后重启Flink集群。
三、Flink SQL 表定义与参数详解
1. 完整建表示例(含元数据列)
sql
-- 启用checkpoint(可选)
SET 'execution.checkpointing.interval' = '5s';
-- 创建PostgreSQL CDC表
CREATE TABLE pg_shipments (
shipment_id INT,
order_id INT,
origin STRING,
destination STRING,
is_arrived BOOLEAN,
-- 元数据列:捕获变更信息
db_name STRING METADATA FROM 'database_name' VIRTUAL,
schema_name STRING METADATA FROM 'schema_name' VIRTUAL,
table_name STRING METADATA FROM 'table_name' VIRTUAL,
op_ts TIMESTAMP_LTZ(3) METADATA FROM 'op_ts' VIRTUAL,
PRIMARY KEY(shipment_id) NOT ENFORCED
) WITH (
'connector' = 'postgres-cdc',
'hostname' = '192.168.1.100',
'port' = '5432',
'username' = 'flinkuser',
'password' = 'flinkpw',
'database-name' = 'postgres',
'schema-name' = 'public',
'table-name' = 'shipments',
'slot.name' = 'flink_slot',
'decoding.plugin.name' = 'decoderbufs',
'changelog-mode' = 'upsert',
'scan.incremental.snapshot.enabled' = 'true'
);
2. 核心参数详解
参数名 | 必选 | 默认值 | 类型 | 说明 |
---|---|---|---|---|
connector |
是 | 无 | String | 固定为postgres-cdc |
hostname |
是 | 无 | String | PostgreSQL服务器IP或域名 |
username |
是 | 无 | String | 连接数据库的用户名(需具备REPLICATION 权限) |
password |
是 | 无 | String | 连接数据库的密码 |
database-name |
是 | 无 | String | 数据库名称(如postgres ) |
schema-name |
是 | 无 | String | 模式名称(如public ) |
table-name |
是 | 无 | String | 表名(如shipments ) |
slot.name |
是 | 无 | String | 逻辑解码槽名称(需提前创建,且每个作业唯一) |
decoding.plugin.name |
否 | decoderbufs |
String | 解码插件:decoderbufs (通用)、pgoutput (PostgreSQL 10+) |
changelog-mode |
否 | all |
String | 变更日志模式:all (全量变更)、upsert (仅插入/更新,需主键) |
scan.incremental.snapshot.enabled |
否 | false | Boolean | 启用增量快照(并行读取,实验性),需配合chunk.key-column 使用 |
heartbeat.interval.ms |
否 | 30s | Duration | 心跳间隔,更新槽位置防止日志被清理 |
四、环境验证与测试
1. 准备测试数据
sql
-- 创建测试表
CREATE TABLE public.shipments (
shipment_id INT PRIMARY KEY,
order_id INT,
origin VARCHAR(50),
destination VARCHAR(50),
is_arrived BOOLEAN,
update_time TIMESTAMP
);
-- 插入测试数据
INSERT INTO public.shipments VALUES
(1, 1001, '北京', '上海', false, NOW()),
(2, 1002, '上海', '广州', true, NOW());
COMMIT;
2. Flink SQL 验证
sql
-- 查询CDC表(首次触发快照读取)
SELECT * FROM pg_shipments;
-- 在PostgreSQL中更新数据
UPDATE public.shipments SET is_arrived = true WHERE shipment_id = 1;
COMMIT;
-- 观察Flink输出:应显示变更记录,op_ts为变更时间
3. DataStream API 验证(并行模式)
java
import org.apache.flink.cdc.connectors.postgres.source.PostgresSourceBuilder;
import org.apache.flink.cdc.debezium.JsonDebeziumDeserializationSchema;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class PostgresCdcExample {
public static void main(String[] args) throws Exception {
// 配置PostgreSQL Source(增量快照模式)
PostgresSourceBuilder.PostgresIncrementalSource<String> sourceBuilder =
PostgresSourceBuilder.postgresIncrementalSource()
.hostname("192.168.1.100")
.port(5432)
.database("postgres")
.schemaList("public")
.tableList("public.shipments")
.username("flinkuser")
.password("flinkpw")
.slotName("flink_slot")
.decodingPluginName("decoderbufs")
.deserializer(new JsonDebeziumDeserializationSchema())
.startupOptions(StartupOptions.initial())
.splitSize(1000) // 快照分片大小
.build();
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(5000);
env.fromSource(
sourceBuilder,
WatermarkStrategy.noWatermarks(),
"Postgres CDC Source")
.setParallelism(4) // 设置4并行度
.print();
env.execute("Postgres CDC Test");
}
}
五、常见问题与解决方案
-
逻辑解码槽冲突
ERROR: replication slot "flink_slot" is already active for PID xxxx
-
解决方案:为每个Flink作业创建唯一槽名,或删除冲突槽:
sqlSELECT pg_drop_replication_slot('flink_slot');
-
-
权限不足
ERROR: must be superuser to create a logical replication slot
- 解决方案:使用超级用户创建槽,或授予用户
CREATEROLE
和CREATEEXTTABLE
权限。
- 解决方案:使用超级用户创建槽,或授予用户
-
增量快照失败(无主键表)
ERROR: Table has no primary key for incremental snapshot
-
解决方案:为表添加主键,或手动指定分片键:
sql'scan.incremental.snapshot.chunk.key-column' = 'shipment_id'
-
-
解码插件不兼容
-
解决方案:PostgreSQL 10+推荐使用
pgoutput
插件:sql'decoding.plugin.name' = 'pgoutput'
-
六、生产环境优化建议
-
WAL日志管理
- 调整
wal_keep_segments
参数(如设为100),避免日志被提前清理导致CDC读取失败。
- 调整
-
槽清理策略
-
定期清理不再使用的槽:
sqlSELECT pg_drop_replication_slot('unused_slot');
-
-
高可用配置
- 使用PostgreSQL流复制集群时,Flink作业需连接主节点,并配置槽在主节点创建。
通过以上步骤,可完成Flink PostgreSQL CDC的全流程配置与验证。生产环境中需特别注意逻辑解码槽的唯一性、WAL日志保留策略及增量快照的并行参数调优,以确保数据一致性和系统稳定性。