Skip to content

PostgreSQL 源端和目标端数据库配置

核心概念

逻辑复制

逻辑复制是PostgreSQL 10+引入的一种复制技术,它基于WAL日志的逻辑内容进行复制,而不是物理块。与物理复制相比,逻辑复制具有以下特点:

  • 粒度更细:可以复制特定的数据库、模式或表
  • 跨版本复制:支持不同PostgreSQL版本之间的复制
  • 从库可写:从库可以写入数据,而不影响复制
  • 选择性复制:可以只复制特定的数据行或列
  • 支持异构系统:可以与其他数据库系统进行数据同步

核心组件

  • 发布者(Publisher):源数据库,负责生成和发送逻辑WAL日志
  • 订阅者(Subscriber):目标数据库,负责接收和应用逻辑WAL日志
  • 发布(Publication):源端数据库上定义的一组要复制的对象(数据库、模式、表)
  • 订阅(Subscription):目标端数据库上定义的对发布的订阅关系
  • 复制槽(Replication Slot):用于确保源端数据库不会删除目标端数据库尚未处理的WAL日志
  • 逻辑解码:将物理WAL日志转换为逻辑格式的过程

逻辑复制的工作原理

  1. 源端数据库将数据库修改记录到WAL日志
  2. 源端数据库的逻辑解码进程将WAL日志转换为逻辑变更
  3. 源端数据库通过复制槽将逻辑变更发送给目标端数据库
  4. 目标端数据库接收逻辑变更并应用到本地数据库
  5. 目标端数据库确认已处理的WAL位置,源端数据库更新复制槽状态

源端数据库配置

启用逻辑复制

bash
# 修改源端数据库的postgresql.conf文件
nano /etc/postgresql/15/main/postgresql.conf

添加或修改以下配置:

txt
# 启用逻辑复制
wal_level = logical          # 必须设置为logical
max_replication_slots = 10   # 最大复制槽数量
max_wal_senders = 10         # 最大WAL发送进程数
max_worker_processes = 16    # 最大工作进程数,影响逻辑解码性能

# 可选:启用WAL压缩
wal_compression = on

重启源端数据库服务

bash
pg_ctl restart -D /var/lib/postgresql/15/main

创建发布

创建发布用户

sql
-- 登录源端数据库数据库
psql -h 源端数据库IP -U postgres

-- 创建发布用户
CREATE USER publisher_user WITH REPLICATION LOGIN ENCRYPTED PASSWORD 'publisher_pass';

-- 授予用户对要复制表的权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO publisher_user;
GRANT USAGE ON SCHEMA public TO publisher_user;

创建发布

sql
-- 创建发布,复制public模式下的所有表
CREATE PUBLICATION my_publication
    FOR ALL TABLES IN SCHEMA public;

-- 或只复制特定表
CREATE PUBLICATION my_publication
    FOR TABLE users, orders, products;

-- 或复制所有表,并自动添加新表
CREATE PUBLICATION my_publication
    FOR ALL TABLES;

-- 查看创建的发布
\dP
SELECT * FROM pg_publication;

向发布中添加或移除表

sql
-- 向发布中添加表
ALTER PUBLICATION my_publication
    ADD TABLE customers;

-- 从发布中移除表
ALTER PUBLICATION my_publication
    DROP TABLE products;

配置pg_hba.conf

bash
# 修改pg_hba.conf文件
nano /etc/postgresql/15/main/pg_hba.conf

添加目标端数据库的连接权限:

txt
# 允许目标端数据库连接到源端数据库
host    replication     publisher_user    目标端数据库IP/32    md5

重新加载配置

bash
pg_ctl reload -D /var/lib/postgresql/15/main

目标端数据库配置

准备目标端数据库

sql
-- 登录目标端数据库
psql -h 目标端数据库IP -U postgres

-- 创建与源端数据库相同的表结构
-- 注意:表结构必须与源端数据库完全匹配
CREATE TABLE users (
    id serial PRIMARY KEY,
    name varchar(100) NOT NULL,
    email varchar(100) UNIQUE NOT NULL,
    created_at timestamp DEFAULT now()
);

-- 创建其他需要复制的表

创建订阅用户

sql
-- 创建订阅用户
CREATE USER subscriber_user WITH ENCRYPTED PASSWORD 'subscriber_pass';

-- 授予用户对目标表的权限
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO subscriber_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO subscriber_user;

创建订阅

sql
-- 创建订阅
CREATE SUBSCRIPTION my_subscription
    CONNECTION 'host=源端数据库IP port=5432 dbname=postgres user=publisher_user password=publisher_pass'
    PUBLICATION my_publication;

-- 查看创建的订阅
\dS
SELECT * FROM pg_subscription;

验证数据同步

sql
-- 在源端数据库上插入测试数据
INSERT INTO users (name, email) VALUES ('测试用户1', 'test1@example.com');
INSERT INTO users (name, email) VALUES ('测试用户2', 'test2@example.com');

-- 在目标端数据库上验证数据是否同步
SELECT * FROM users;

订阅的高级配置

启用/禁用订阅

sql
-- 禁用订阅
ALTER SUBSCRIPTION my_subscription DISABLE;

-- 启用订阅
ALTER SUBSCRIPTION my_subscription ENABLE;

刷新订阅

当源端数据库添加了新表到发布中时,需要刷新订阅:

sql
-- 刷新订阅,获取新添加的表
ALTER SUBSCRIPTION my_subscription REFRESH PUBLICATION;

删除订阅

sql
-- 删除订阅
DROP SUBSCRIPTION my_subscription;

高级配置与管理

复制槽管理

sql
-- 查看复制槽状态
SELECT * FROM pg_replication_slots;

-- 手动创建逻辑复制槽
SELECT * FROM pg_create_logical_replication_slot('my_logical_slot', 'pgoutput');

-- 删除复制槽
SELECT pg_drop_replication_slot('my_logical_slot');

冲突处理

逻辑复制中可能出现数据冲突,需要配置冲突处理策略:

sql
-- 设置冲突处理策略
-- error: 遇到冲突时报错(默认)
-- skip: 跳过冲突的变更
-- last_update_wins: 最后更新的记录获胜

-- 在目标端数据库上配置
ALTER SUBSCRIPTION my_subscription SET (
    conflict_resolution = 'last_update_wins'
);

性能优化

源端数据库优化

sql
-- 增加WAL发送进程数
ALTER SYSTEM SET max_wal_senders = 20;

-- 增加复制槽数量
ALTER SYSTEM SET max_replication_slots = 20;

-- 优化逻辑解码性能
ALTER SYSTEM SET max_worker_processes = 32;
ALTER SYSTEM SET wal_level = logical;

目标端数据库优化

sql
-- 增加应用进程数
ALTER SYSTEM SET max_parallel_workers_per_gather = 8;

-- 调整同步提交级别
ALTER SYSTEM SET synchronous_commit = 'remote_write';

监控逻辑复制

监控源端数据库

sql
-- 查看发布状态
SELECT * FROM pg_stat_publication;

-- 查看发布表状态
SELECT * FROM pg_stat_publication_tables;

-- 查看复制槽状态
SELECT * FROM pg_replication_slots WHERE slot_type = 'logical';

监控目标端数据库

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

-- 查看订阅表状态
SELECT * FROM pg_stat_subscription_tables;

最佳实践

配置最佳实践

  • 合理设置wal_level:确保设置为logical,启用逻辑复制
  • 足够的复制槽:根据目标端数据库数量设置合理的max_replication_slots
  • 适当的WAL发送进程:根据目标端数据库数量设置max_wal_senders
  • 优化逻辑解码:增加max_worker_processes提高逻辑解码性能
  • 使用复制槽:确保源端数据库不会删除目标端数据库尚未处理的WAL日志
  • 配置冲突处理策略:根据业务需求选择合适的冲突处理策略

安全最佳实践

  • 使用专用用户:为逻辑复制创建专用的源端数据库和目标端数据库用户
  • 最小权限原则:只授予复制所需的最小权限
  • 使用强密码:为复制用户设置强密码
  • 限制网络访问:在pg_hba.conf中限制目标端数据库的IP访问范围
  • 启用SSL:在生产环境中启用SSL加密复制连接

运维最佳实践

  • 定期监控:监控源端数据库和目标端数据库的复制状态
  • 定期备份:定期备份源端数据库和目标端数据库
  • 测试复制:定期测试复制的完整性和性能
  • 文档化配置:详细记录逻辑复制的配置和管理流程
  • 版本兼容性:确保源端数据库和目标端数据库版本兼容(建议使用相同版本)
  • 避免大事务:大事务会导致复制延迟,尽量避免

性能最佳实践

  • 合理分区表:对大表进行分区,提高复制性能
  • 优化WAL生成:调整checkpoint配置,减少WAL生成量
  • 启用WAL压缩:减少网络传输量
  • 使用并行复制:优化目标端数据库的并行应用配置
  • 合理设置同步提交级别:根据业务需求选择合适的同步提交级别

常见问题(FAQ)

Q1:逻辑复制和物理复制有什么区别?

A1:主要区别如下:

特性物理复制逻辑复制
复制粒度整个数据库数据库、模式、表、行、列
从库状态只读可写
跨版本复制有限支持良好支持
异构系统支持不支持支持
配置复杂度简单复杂
性能相对较低

Q2:如何选择发布和订阅的表?

A2:可以根据以下原则选择:

  • 只复制需要同步的表,减少复制开销
  • 考虑表的大小和更新频率,避免复制过大或更新频繁的表
  • 确保发布和订阅的表结构完全一致
  • 对于大表,考虑使用分区表提高复制性能

Q3:逻辑复制出现冲突怎么办?

A3:可以采取以下措施:

  • 检查冲突原因,修复数据不一致
  • 配置合适的冲突处理策略
  • 重新初始化订阅
  • 确保目标端数据库上的应用不会修改复制的表

Q4:如何重新初始化订阅?

A4:可以按照以下步骤重新初始化:

  1. 删除现有订阅
  2. 清理目标端数据库上的复制数据
  3. 重新创建订阅
  4. 验证数据同步

Q5:逻辑复制支持DDL复制吗?

A5:PostgreSQL 14+开始支持DDL复制,但需要使用pgoutput插件并配置合适的参数:

sql
-- 创建发布时包含DDL
CREATE PUBLICATION my_publication
    FOR ALL TABLES
    WITH (publish_via_partition_root = true, publish_ddl = 'table');

Q6:如何监控逻辑复制的延迟?

A6:可以使用以下方法:

sql
-- 在目标端数据库上查看复制延迟
SELECT 
    subscription_name,
    now() - last_msg_receipt_time AS last_msg_delay,
    last_sync_time,
    now() - last_sync_time AS sync_delay
FROM pg_stat_subscription;

Q7:逻辑复制可以用于数据迁移吗?

A7:是的,逻辑复制可以用于数据迁移,特别是跨版本迁移:

  1. 在源数据库上创建发布
  2. 在目标数据库上创建订阅
  3. 等待数据同步完成
  4. 切换应用到目标数据库
  5. 停止并删除复制关系

Q8:如何处理大表的初始同步?

A8:对于大表,可以采取以下方法:

  • 使用pg_dump/pg_restore进行初始数据加载
  • 然后创建订阅,从当前WAL位置开始复制
  • 或者使用pg_basebackup创建基础备份,然后配置逻辑复制

逻辑复制的应用场景

  1. 数据仓库同步:将生产数据库的数据同步到数据仓库
  2. 跨版本升级:在不同PostgreSQL版本之间迁移数据
  3. 读写分离:将特定表的读写分离到不同数据库
  4. 多活架构:构建多活数据库架构
  5. 数据集成:与其他数据库系统进行数据集成
  6. 微服务数据同步:在微服务架构中同步数据
  7. 数据备份:作为数据备份的补充
  8. 测试环境同步:将生产数据同步到测试环境

通过合理配置和管理PostgreSQL源端数据库与目标端数据库,可以构建灵活、高效的数据复制架构,满足不同业务场景的需求。