PostgreSQL逻辑复制Slot管理与跨版本数据同步配置实战

PostgreSQL逻辑复制(Logical Replication)从10版本开始原生支持,与物理流复制不同,逻辑复制工作在表级别,以发布/订阅模型传输INSERT/UPDATE/DELETE操作的逻辑变更,不依赖Block级别的WAL一致性。这一特性使其在跨版本升级、异构数据库同步、读写分离等场景中具有独特优势。本文围绕逻辑复制Slot的配置、数据同步拓扑搭建和常见故障排查展开。

PostgreSQL逻辑复制与物理流复制架构对比

物理流复制传输WAL日志的原始Block变更,备库是主库的字节级副本,要求主备版本一致、架构一致。逻辑复制则通过逻辑解码插件(pgoutput)将WAL解析为行级别的变更事件,订阅端解析后执行SQL:

特性 物理流复制 逻辑复制
复制粒度 整个实例 选定的表
版本要求 必须同版本 支持跨版本
备库可写 不可写(只读) 可写
复制内容 所有变更(含DDL) 仅DML(INSERT/UPDATE/DELETE)
跨平台 不支持 支持(不同OS/架构)
网络中断恢复 自动追WAL 依赖Replication Slot

逻辑复制不支持DDL复制(建表、改表结构需手动同步),这是其主要限制。但在跨版本平滑升级(如PG13升PG16)、数据订阅消费(同步到ES/数仓)等场景中,逻辑复制是唯一原生方案。

逻辑复制发布端配置与WAL日志格式设置

逻辑复制要求主库将wal_level设置为logical,并调整WAL相关参数:

-- postgresql.conf (发布端)
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
max_worker_processes = 20

-- 重载配置
SELECT pg_reload_conf();

-- 确认逻辑复制已启用
SHOW wal_level;
-- 应返回: logical

创建发布(Publication),指定要复制的表和操作类型:

-- 创建发布,包含所有表的所有DML操作
CREATE PUBLICATION pub_app_data FOR ALL TABLES;

-- 精确指定表和操作
CREATE PUBLICATION pub_orders FOR TABLE 
    orders, order_items, customers 
    WITH (publish = 'insert, update, delete');

-- 添加/移除表
ALTER PUBLICATION pub_orders ADD TABLE products;
ALTER PUBLICATION pub_orders DROP TABLE customers;

-- 查看发布状态
SELECT * FROM pg_publication;
SELECT * FROM pg_publication_tables;

被复制的表必须有REPLICA IDENTITY——用于标识UPDATE/DELETE操作对应行的主键或唯一索引。默认使用主键:

-- 无主键的表需设置replica identity
ALTER TABLE orders REPLICA IDENTITY USING INDEX idx_orders_no;

-- 查看所有表的replica identity设置
SELECT relname, relreplident 
FROM pg_class 
WHERE relkind = 'r' AND relname IN ('orders', 'order_items');

relreplident值含义:d=默认(主键)、f=full(整行)、i=索引、n=无。设置为full时逻辑复制会传输整行作为匹配条件,对宽表性能影响较大。

逻辑复制Slot创建与订阅端数据初始化

订阅端需要创建订阅(Subscription),指定连接信息和订阅的发布名称:

-- 订阅端 PostgreSQL 配置
-- postgresql.conf
max_replication_slots = 10
max_logical_replication_workers = 10
max_worker_processes = 20

-- 创建数据库和表结构(需手动同步结构)
CREATE DATABASE app_data;

-- 在订阅端创建与发布端一致的表结构
-- (DDL不会自动复制,必须手动执行)

-- 创建订阅
CREATE SUBSCRIPTION sub_app_data
    CONNECTION 'host=10.0.1.10 port=5432 dbname=app_data user=replicator password=xxx'
    PUBLICATION pub_app_data
    WITH (
        copy_data = true,           -- 初始化时同步现有数据
        create_slot = true,          -- 自动创建replication slot
        enabled = true,
        slot_name = 'sub_app_data_slot',
        synchronous_commit = on
    );

-- 查看订阅状态
SELECT * FROM pg_subscription;
SELECT * FROM pg_stat_subscription;

copy_data = true会在创建订阅时执行一次COPY操作,将发布端现有数据同步到订阅端。对于大表,这个初始同步会占用较多IO和网络带宽,建议在低峰期执行。

跨版本数据同步与无缝迁移操作流程

逻辑复制最典型的应用场景是PostgreSQL跨大版本升级。以PG13迁移到PG16为例:

# 步骤1: 准备PG16新实例,导入表结构
pg_dump -h old-pg13-host -U postgres --schema-only --no-owner app_data |     psql -h new-pg16-host -U postgres app_data

# 步骤2: 在PG13上创建发布
psql -h old-pg13-host -U postgres -d app_data -c "
    CREATE PUBLICATION pub_migration FOR ALL TABLES;
"

# 步骤3: 在PG16上创建订阅,启用初始数据同步
psql -h new-pg16-host -U postgres -d app_data -c "
    CREATE SUBSCRIPTION sub_migration
        CONNECTION 'host=old-pg13-host port=5432 dbname=app_data user=replicator password=xxx'
        PUBLICATION pub_migration
        WITH (copy_data = true, create_slot = true);
"

# 步骤4: 监控同步进度
watch -n 5 "psql -h new-pg16-host -U postgres -d app_data -c "
    SELECT subname, received_lsn, latest_end_lsn, 
           latest_end_time,
           NOW() - latest_end_time AS replication_lag
    FROM pg_stat_subscription;
""

# 步骤5: 同步追上后,切换应用连接到PG16,然后删除订阅
psql -h new-pg16-host -U postgres -d app_data -c "
    ALTER SUBSCRIPTION sub_migration DISABLE;
    DROP SUBSCRIPTION sub_migration;
"

逻辑复制Slot积压故障排查与WAL膨胀处理

逻辑复制最常见的故障是Replication Slot积压导致WAL文件无限增长。当订阅端长时间宕机,主库为保持WAL不被回收,pg_wal目录会持续膨胀直到磁盘满。

-- 检查所有slot的状态和WAL积压量
SELECT slot_name, plugin, slot_type, active, 
       restart_lsn, 
       pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS lag_bytes,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag_pretty
FROM pg_replication_slots;

-- 输出示例:
-- slot_name         | active | lag_bytes | lag_pretty
-- sub_app_data_slot | f      |  8589934592 | 8192 MB
-- (active=f表示订阅端未连接,积压了8GB WAL)

处理方案:

-- 方案1: 临时推进slot的确认位置(跳过积压的WAL,数据会丢失)
SELECT pg_replication_slot_advance('sub_app_data_slot', pg_current_wal_lsn());

-- 方案2: 如果订阅端已永久不可用,删除slot
SELECT pg_drop_replication_slot('sub_app_data_slot');

-- 方案3: 设置最大WAL保留,防止磁盘满(PG13+)
-- postgresql.conf
-- max_slot_wal_keep_size = 10GB  -- slot最多保留10GB WAL,超出后slot变为inactive

-- 监控告警:WAL积压超过1GB告警
SELECT slot_name, 
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag
FROM pg_replication_slots 
WHERE pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) > 1073741824;

生产环境中建议为每个逻辑复制配置max_slot_wal_keep_size,避免单个故障订阅拖垮主库。配合监控告警(Prometheus + postgres_exporter的pg_replication_slots指标),在积包量超过阈值时及时介入处理。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/postgresql-luo-ji-fu-zhi-slot-guan-li-yu-kua-ban-ben-shu-ju/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐