外观
PostgreSQL 逻辑复制配置
逻辑复制是 PostgreSQL 10 引入的革命性复制机制,基于发布/订阅模型,允许选择性复制数据,支持跨版本、跨实例甚至跨数据库系统的复制。它为 PostgreSQL 提供了更灵活的数据分发能力,是构建现代数据架构的重要工具。
逻辑复制概述
什么是逻辑复制
逻辑复制是一种基于事务日志的复制机制,它捕获数据库中的数据更改事件(INSERT、UPDATE、DELETE),并将这些更改作为逻辑事件流发送给订阅者。与物理复制不同,逻辑复制不复制整个数据库集群,而是允许:
- 选择性复制特定表或表的特定列
- 选择性复制特定操作(如仅复制 INSERT 和 UPDATE,不复制 DELETE)
- 在不同版本的 PostgreSQL 之间复制
- 在不同数据库实例或系统之间复制
- 对复制的数据进行转换和过滤
逻辑复制的核心优势
- 高度灵活性:支持表级、列级和操作级的选择性复制
- 跨版本兼容:支持不同 PostgreSQL 版本之间的复制,便于升级迁移
- 跨系统集成:可以与其他数据库系统或应用程序集成
- 动态配置:支持动态添加或移除发布和订阅,无需重建复制环境
- 细粒度冲突处理:提供多种冲突处理策略,适应不同业务场景
- 并行应用能力:PostgreSQL 12+ 支持并行应用复制数据,提高性能
- 低资源消耗:只复制必要的数据,减少网络流量和存储空间
逻辑复制的典型使用场景
- 数据集成:将多个业务数据库的数据复制到数据仓库或数据湖
- 跨版本升级:在不同 PostgreSQL 版本之间平滑迁移数据
- 微服务架构:在不同微服务之间共享核心数据
- 读写分离:将热点表的查询负载分散到多个只读实例
- 数据分片:将大型表分散到多个 PostgreSQL 实例
- 灾备与备份:实现选择性数据备份和恢复
- 多租户架构:将租户数据复制到独立的数据库实例
- 实时数据同步:实现业务系统与分析系统的实时数据同步
逻辑复制架构
核心组件
- 发布者(Publisher):产生并发送数据更改事件的 PostgreSQL 实例
- 订阅者(Subscriber):接收并应用数据更改事件的 PostgreSQL 实例
- 发布(Publication):发布者上定义的一组要复制的表和操作
- 订阅(Subscription):订阅者上定义的对特定发布的订阅关系
- 复制槽(Replication Slot):确保发布者保留订阅者尚未接收的数据
- WAL 发送器:将 WAL 日志转换为逻辑事件流并发送给订阅者
- 逻辑复制工作进程:在订阅者上应用逻辑事件的工作进程
- 复制原点(Replication Origin):跟踪订阅者应用的 WAL 位置
工作原理
- 发布定义:在发布者上创建发布,指定要复制的表、列和操作
- 订阅创建:在订阅者上创建订阅,指定要订阅的发布和连接信息
- 初始数据同步:可选地从发布者复制初始数据(COPY 操作)
- WAL 捕获:发布者捕获数据更改的 WAL 日志,并转换为逻辑格式
- 事件流传输:通过网络将逻辑事件流发送给订阅者
- 并行应用:订阅者使用多个工作进程并行应用逻辑事件
- 冲突处理:根据配置的策略处理可能的数据冲突
- 状态追踪:使用复制槽和复制原点追踪复制进度
逻辑复制配置
环境准备
生产环境硬件要求
逻辑复制对硬件资源的要求取决于复制的数据量和频率,以下是不同规模场景的推荐配置:
| 场景 | CPU | 内存 | 存储 | 网络 |
|---|---|---|---|---|
| 小规模场景 | 4 核 | 16 GB | 200 GB NVMe SSD | 万兆以太网 |
| 中等规模场景 | 8 核 | 32 GB | 500 GB NVMe SSD | 万兆以太网 |
| 大规模场景 | 16 核+ | 64 GB+ | 1 TB+ NVMe SSD | 25/100 千兆以太网 |
软件要求
| 软件 | 版本要求 | 生产建议 |
|---|---|---|
| PostgreSQL | 12 或以上 | 推荐 PostgreSQL 14-16,获得更好的性能和新特性支持 |
| 操作系统 | RHEL/CentOS 8+, Ubuntu 20.04+, Debian 11+ | 推荐 RHEL 9 或 Ubuntu 22.04 LTS |
| 内核版本 | Linux 4.18+ | 推荐 Linux 5.10+,支持更多性能优化 |
生产环境节点规划
本示例部署 1 个发布者和 2 个订阅者的逻辑复制环境:
| 节点角色 | 主机名 | IP 地址 | 用途 | 配置 |
|---|---|---|---|---|
| 发布者 | pg-publisher | 192.168.1.10 | 核心业务数据库 | 8 核/32 GB/500 GB NVMe |
| 订阅者 1 | pg-subscriber-analytics | 192.168.1.11 | 数据仓库同步 | 16 核/64 GB/1 TB NVMe |
| 订阅者 2 | pg-subscriber-readonly | 192.168.1.12 | 读写分离 | 8 核/32 GB/500 GB NVMe |
预配置检查
在配置逻辑复制前,确保满足以下条件:
- 数据库版本:发布者版本 ≤ 订阅者版本
- 表结构:订阅者上的表结构必须与发布者兼容
- 主键约束:所有要复制的表必须有主键或唯一约束
- WAL 配置:发布者必须将 wal_level 设置为 logical
- 权限配置:复制用户必须具有适当的权限
- 网络连通性:发布者和订阅者之间网络连通
- 防火墙配置:确保 5432 端口允许访问
发布者配置
1. 安装 PostgreSQL
在所有节点上安装 PostgreSQL 15(推荐版本):
CentOS/RHEL 安装:
bash
# 添加 PostgreSQL 仓库
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# 安装 PostgreSQL 15
yum install -y postgresql15 postgresql15-server postgresql15-contrib postgresql15-libsUbuntu/Debian 安装:
bash
# 添加 PostgreSQL 仓库
sudo apt-get update
sudo apt-get install -y gnupg2 wget
echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# 安装 PostgreSQL 15
sudo apt-get update
sudo apt-get install -y postgresql-15 postgresql-15-contrib2. 初始化发布者
bash
# 初始化数据库
/usr/pgsql-15/bin/postgresql-15-setup initdb
# 启动并启用 PostgreSQL 服务
systemctl start postgresql-15
systemctl enable postgresql-153. 配置发布者核心参数
编辑 /var/lib/pgsql/15/data/postgresql.conf 文件,以下是生产环境推荐配置:
ini
# 基本配置
listen_addresses = '*' # 允许所有 IP 访问
port = 5432
# WAL 配置(逻辑复制必须配置)
wal_level = logical # 必须设置为 logical 才能启用逻辑复制
max_wal_senders = 20 # 允许的最大 WAL 发送进程数
max_replication_slots = 20 # 允许的最大复制槽数量
wal_keep_size = 16GB # 保留的 WAL 日志大小
wal_compression = on # 启用 WAL 压缩(PostgreSQL 14+)
# 逻辑复制配置
max_worker_processes = 16 # 允许的最大后台进程数
max_logical_replication_workers = 8 # 允许的最大逻辑复制工作进程数
max_sync_workers_per_subscription = 4 # 每个订阅的最大同步工作进程数
# 性能优化
shared_buffers = 8GB # 共享内存缓冲区,建议为系统内存的 25%
work_mem = 4MB # 每个工作进程的内存
maintenance_work_mem = 1GB # 维护操作的内存4. 配置发布者认证
编辑 /var/lib/pgsql/15/data/pg_hba.conf 文件,添加复制用户访问权限:
# 允许复制用户从订阅者访问
host replication replicator 192.168.1.11/32 scram-sha-256
host replication replicator 192.168.1.12/32 scram-sha-256
# 允许应用用户访问
host appdb appuser 10.0.0.0/8 scram-sha-256
# 本地连接配置
local all postgres peer
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256安全最佳实践:
- 使用
scram-sha-256替代md5进行密码认证 - 严格限制复制用户的访问 IP 范围
- 避免使用
0.0.0.0/0开放所有 IP 访问
5. 创建复制用户和测试数据
bash
# 切换到 postgres 用户
sudo -u postgres psqlsql
-- 创建复制用户
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'StrongPassword123!';
-- 创建测试数据库
CREATE DATABASE appdb;
\c appdb;
-- 创建测试表
CREATE TABLE users (
id serial primary key,
name varchar(100) not null,
email varchar(100) unique not null,
status varchar(20) default 'active',
created_at timestamp default current_timestamp,
updated_at timestamp default current_timestamp
);
CREATE TABLE orders (
id serial primary key,
user_id integer references users(id),
amount numeric(10,2) not null,
status varchar(20) default 'pending',
created_at timestamp default current_timestamp,
updated_at timestamp default current_timestamp
);
-- 添加更新时间触发器
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_orders_updated_at BEFORE UPDATE ON orders FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- 插入测试数据
INSERT INTO users (name, email) VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Charlie', 'charlie@example.com');
INSERT INTO orders (user_id, amount) VALUES
(1, 100.00),
(2, 200.00),
(3, 300.00);6. 创建发布
在发布者上创建不同类型的发布,适应不同的业务需求:
sql
-- 连接到测试数据库
\c appdb;
-- 1. 创建包含所有表的发布
CREATE PUBLICATION all_tables;
-- 将表添加到发布
ALTER PUBLICATION all_tables ADD TABLE users;
ALTER PUBLICATION all_tables ADD TABLE orders;
-- 2. 创建只包含特定操作的发布
CREATE PUBLICATION users_insert_update FOR TABLE users
WITH (publish = 'insert, update');
-- 3. 创建包含特定列的发布
CREATE PUBLICATION users_basic FOR TABLE users (id, name, status, created_at);
-- 4. 创建包含所有操作的发布
CREATE PUBLICATION orders_full FOR TABLE orders
WITH (publish = 'insert, update, delete');
-- 5. 创建包含 WHERE 条件过滤的发布(PostgreSQL 15+)
-- CREATE PUBLICATION active_users FOR TABLE users
-- WHERE (status = 'active');
-- 查看所有发布
\dRp+;发布配置说明:
publish参数:控制要复制的操作类型(insert, update, delete, truncate)- 表级发布:可以指定特定表和列
- 发布级过滤:PostgreSQL 15+ 支持 WHERE 条件过滤
订阅者配置
1. 初始化订阅者
在所有订阅者节点上初始化 PostgreSQL:
bash
# 初始化数据库
/usr/pgsql-15/bin/postgresql-15-setup initdb
# 启动并启用 PostgreSQL 服务
systemctl start postgresql-15
systemctl enable postgresql-152. 配置订阅者参数
编辑 /var/lib/pgsql/15/data/postgresql.conf 文件:
ini
# 基本配置
listen_addresses = '*'
port = 5432
# 逻辑复制配置
max_worker_processes = 16
max_logical_replication_workers = 8
max_sync_workers_per_subscription = 4 # 并行应用工作进程数
max_parallel_workers_per_gather = 4
# 性能优化
shared_buffers = 8GB
work_mem = 4MB
maintenance_work_mem = 1GB3. 创建目标数据库和表结构
在订阅者上创建与发布者兼容的数据库和表结构:
sql
-- 创建数据库
CREATE DATABASE appdb;
\c appdb;
-- 创建与发布者兼容的表结构
CREATE TABLE users (
id serial primary key,
name varchar(100) not null,
email varchar(100) unique not null,
status varchar(20) default 'active',
created_at timestamp default current_timestamp,
updated_at timestamp default current_timestamp
);
CREATE TABLE orders (
id serial primary key,
user_id integer references users(id),
amount numeric(10,2) not null,
status varchar(20) default 'pending',
created_at timestamp default current_timestamp,
updated_at timestamp default current_timestamp
);
-- 添加与发布者相同的触发器
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_orders_updated_at BEFORE UPDATE ON orders FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();4. 创建订阅
在订阅者上创建订阅,连接到发布者:
sql
-- 在分析订阅者(pg-subscriber-analytics)上创建订阅
CREATE SUBSCRIPTION sub_all_tables
CONNECTION 'host=pg-publisher port=5432 dbname=appdb user=replicator password=StrongPassword123!'
PUBLICATION all_tables
WITH (
copy_data = true, -- 复制初始数据
create_slot = true, -- 自动创建复制槽
enabled = true, -- 创建后立即启用
refresh_publication = true, -- 自动刷新发布信息
conflict_resolution = 'last_update_wins' -- 冲突处理策略(PostgreSQL 14+)
);
-- 在只读订阅者(pg-subscriber-readonly)上创建订阅
CREATE SUBSCRIPTION sub_readonly
CONNECTION 'host=pg-publisher port=5432 dbname=appdb user=replicator password=StrongPassword123!'
PUBLICATION users_insert_update, orders_full
WITH (
copy_data = true,
create_slot = true,
enabled = true,
refresh_publication = true
);
-- 查看订阅状态
SELECT * FROM pg_subscription;
SELECT * FROM pg_stat_subscription;订阅配置参数说明:
copy_data:是否复制初始数据(默认为 true)create_slot:是否自动创建复制槽(默认为 true)enabled:创建后是否立即启用订阅(默认为 true)refresh_publication:是否自动刷新发布信息(默认为 false)conflict_resolution:冲突处理策略(PostgreSQL 14+)synchronous_commit:订阅者的同步提交级别
验证逻辑复制
1. 检查初始数据同步
在订阅者上检查是否已同步发布者的初始数据:
sql
-- 在订阅者上执行
\c appdb;
-- 检查用户表数据
SELECT * FROM users;
-- 检查订单表数据
SELECT * FROM orders;2. 测试数据更改复制
在发布者上修改数据,然后在订阅者上检查是否已复制:
发布者上执行数据更改:
sql
-- 连接到发布者的 appdb 数据库
\c appdb;
-- 插入新用户
INSERT INTO users (name, email) VALUES ('David', 'david@example.com');
-- 更新订单状态
UPDATE orders SET status = 'paid' WHERE id = 1;
-- 删除测试订单
DELETE FROM orders WHERE id = 3;订阅者上验证复制结果:
sql
-- 在订阅者上执行
\c appdb;
-- 检查新用户是否已复制
SELECT * FROM users WHERE name = 'David';
-- 检查订单状态是否已更新
SELECT * FROM orders WHERE id = 1;
-- 检查订单是否已删除
SELECT * FROM orders WHERE id = 3;3. 检查复制状态
在发布者上检查复制状态:
sql
-- 查看复制槽状态
SELECT * FROM pg_replication_slots WHERE slot_type = 'logical';
-- 查看 WAL 发送器状态
SELECT * FROM pg_stat_replication;在订阅者上检查复制状态:
sql
-- 查看订阅状态
SELECT * FROM pg_stat_subscription;
-- 查看订阅详情
SELECT * FROM pg_subscription;
SELECT * FROM pg_subscription_rel;逻辑复制高级配置
1. 动态管理发布与订阅
修改发布:
sql
-- 添加表到发布
ALTER PUBLICATION all_tables ADD TABLE new_table;
-- 从发布中移除表
ALTER PUBLICATION all_tables DROP TABLE old_table;
-- 修改发布的 publish 参数
ALTER PUBLICATION users_insert_update SET (publish = 'insert, update, delete');
-- 删除发布
DROP PUBLICATION IF EXISTS old_publication;修改订阅:
sql
-- 添加发布到订阅
ALTER SUBSCRIPTION sub_all_tables ADD PUBLICATION new_publication;
-- 从订阅中移除发布
ALTER SUBSCRIPTION sub_all_tables DROP PUBLICATION old_publication;
-- 刷新订阅的发布信息
ALTER SUBSCRIPTION sub_all_tables REFRESH PUBLICATION;
-- 禁用订阅
ALTER SUBSCRIPTION sub_all_tables DISABLE;
-- 启用订阅
ALTER SUBSCRIPTION sub_all_tables ENABLE;
-- 删除订阅
DROP SUBSCRIPTION IF EXISTS old_subscription;2. 冲突处理策略
PostgreSQL 14+ 支持多种冲突处理策略:
sql
-- 创建订阅时指定冲突处理策略
CREATE SUBSCRIPTION sub_with_conflict_resolution
CONNECTION 'host=pg-publisher port=5432 dbname=appdb user=replicator password=StrongPassword123!'
PUBLICATION all_tables
WITH (
copy_data = true,
conflict_resolution = 'last_update_wins' -- 冲突处理策略
);可用的冲突处理策略:
| 策略 | 描述 |
|---|---|
| error | 遇到冲突时报错(默认) |
| last_update_wins | 保留最后更新的数据(基于 updated_at 字段) |
| first_update_wins | 保留最先更新的数据 |
| keep_local | 保留本地数据,忽略发布者数据 |
| overwrite_local | 用发布者数据覆盖本地数据 |
手动处理冲突:
sql
-- 1. 禁用订阅
ALTER SUBSCRIPTION sub_all_tables DISABLE;
-- 2. 查看冲突信息
SELECT * FROM pg_stat_subscription;
-- 3. 修复冲突数据
-- 例如,删除冲突行
DELETE FROM users WHERE id = 1;
-- 4. 启用订阅
ALTER SUBSCRIPTION sub_all_tables ENABLE;3. 并行逻辑复制
PostgreSQL 12+ 支持并行应用逻辑复制数据,提高订阅者的应用性能:
sql
-- 创建订阅时启用并行应用
CREATE SUBSCRIPTION sub_parallel
CONNECTION 'host=pg-publisher port=5432 dbname=appdb user=replicator password=StrongPassword123!'
PUBLICATION all_tables
WITH (
copy_data = true,
max_sync_workers_per_subscription = 4 -- 并行工作进程数
);并行复制最佳实践:
- 根据 CPU 核心数调整
max_sync_workers_per_subscription - 对于大型表,并行复制可以显著提高应用性能
- 监控订阅者的 CPU 使用率,避免过度并行
4. 跨版本逻辑复制
逻辑复制支持不同 PostgreSQL 版本之间的复制,允许在升级时逐步迁移数据。
版本兼容性矩阵:
| 发布者版本 | 订阅者版本 | 支持情况 |
|---|---|---|
| 10 | 10-16 | 支持 |
| 11 | 11-16 | 支持 |
| 12 | 12-16 | 支持 |
| 13 | 13-16 | 支持 |
| 14 | 14-16 | 支持 |
| 15 | 15-16 | 支持 |
| 16 | 16 | 支持 |
跨版本复制注意事项:
- 发布者版本 ≤ 订阅者版本
- 表结构兼容:确保订阅者的表结构与发布者兼容
- 数据类型兼容:注意不同版本之间的数据类型差异
- 功能兼容性:新功能(如 JSONB 增强)可能不被旧版本支持
- 测试验证:先测试小批量数据复制,再进行大规模复制
- 性能影响:跨版本复制可能会有一定的性能开销
跨版本升级示例:
- 部署新的 PostgreSQL 16 订阅者
- 在旧的 PostgreSQL 13 发布者上配置逻辑复制
- 创建订阅,复制所有数据
- 验证数据一致性
- 切换应用连接到新的 PostgreSQL 16 实例
- 将新实例设置为发布者,旧实例设置为订阅者(可选)
5. 选择性复制配置
只复制特定操作:
sql
-- 创建只复制 INSERT 和 UPDATE 操作的发布
CREATE PUBLICATION users_insert_update FOR TABLE users
WITH (publish = 'insert, update');
-- 创建只复制 DELETE 操作的发布
CREATE PUBLICATION users_delete FOR TABLE users
WITH (publish = 'delete');只复制特定列:
sql
-- 创建只复制特定列的发布
CREATE PUBLICATION users_basic FOR TABLE users (id, name, status, created_at);过滤特定行(PostgreSQL 15+):
sql
-- 创建只复制活跃用户的发布
CREATE PUBLICATION active_users FOR TABLE users
WHERE (status = 'active');逻辑复制监控与管理
1. 内置视图监控
PostgreSQL 提供了丰富的内置视图用于监控逻辑复制:
发布者监控视图:
sql
-- 查看所有发布
SELECT * FROM pg_publication;
-- 查看发布包含的表
SELECT * FROM pg_publication_tables;
-- 查看逻辑复制槽状态
SELECT * FROM pg_replication_slots WHERE slot_type = 'logical';
-- 查看 WAL 发送器状态
SELECT * FROM pg_stat_replication;订阅者监控视图:
sql
-- 查看所有订阅
SELECT * FROM pg_subscription;
-- 查看订阅的表映射
SELECT * FROM pg_subscription_rel;
-- 查看订阅状态统计
SELECT * FROM pg_stat_subscription;
-- 查看逻辑复制工作进程
SELECT * FROM pg_stat_activity WHERE backend_type = 'logical replication worker';2. 日志监控
配置 PostgreSQL 日志记录逻辑复制相关信息:
ini
# postgresql.conf
log_replication_commands = on
log_replication_connections = on
log_min_messages = warning
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '查看逻辑复制日志:
bash
# 查看最近的逻辑复制日志
tail -f /var/lib/pgsql/15/data/log/postgresql-*.log | grep -i logical
# 查看复制槽相关日志
tail -f /var/lib/pgsql/15/data/log/postgresql-*.log | grep -i replication_slot3. Prometheus + Grafana 监控
使用 pg_exporter 监控逻辑复制状态:
安装 pg_exporter:
bash
# 下载并安装 pg_exporter
download_url=$(curl -s https://api.github.com/repos/prometheus-community/postgres_exporter/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4)
wget $download_url -O pg_exporter.tar.gz
tar xzf pg_exporter.tar.gz
cd pg_exporter-*
cp pg_exporter /usr/local/bin/
# 创建服务文件
cat > /etc/systemd/system/pg_exporter.service <<EOF
[Unit]
Description=PostgreSQL Exporter for Prometheus
After=network.target postgresql.service
[Service]
Type=simple
User=postgres
Environment=DATA_SOURCE_NAME=postgresql://postgres@localhost:5432/postgres?sslmode=disable
ExecStart=/usr/local/bin/pg_exporter --web.listen-address=:9187 --web.telemetry-path=/metrics
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 启动服务
systemctl daemon-reload
systemctl enable pg_exporter
systemctl start pg_exporterGrafana 监控面板:
- 使用官方 PostgreSQL 仪表盘(ID: 9628)
- 添加自定义逻辑复制监控面板:
- 订阅状态监控
- 复制延迟监控
- 冲突统计监控
- 逻辑复制工作进程状态
- 复制槽状态监控
4. 复制槽管理
查看复制槽状态:
sql
-- 查看所有逻辑复制槽
SELECT
slot_name,
slot_type,
active,
active_pid,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal,
age(now(), pg_stat_get_replication_slot_xact_bytes(slot_name)) AS inactive_time
FROM pg_replication_slots
WHERE slot_type = 'logical';删除无效复制槽:
sql
-- 删除不活跃的复制槽
SELECT pg_drop_replication_slot('inactive_slot');自动清理脚本:
创建定期清理无效复制槽的脚本:
bash
#!/bin/bash
# 清理超过7天未活动的逻辑复制槽
sudo -u postgres psql -c "
DO $$
DECLARE
rec RECORD;
BEGIN
FOR rec IN
SELECT slot_name
FROM pg_replication_slots
WHERE slot_type = 'logical'
AND NOT active
AND age(now(), pg_stat_get_replication_slot_xact_bytes(slot_name)) > interval '7 days'
LOOP
EXECUTE format('SELECT pg_drop_replication_slot(%L)', rec.slot_name);
RAISE NOTICE 'Dropped inactive logical slot: %', rec.slot_name;
END LOOP;
END $$;
"5. 性能优化
发布者性能优化:
- 合理设置
wal_level = logical - 调整
max_wal_senders和max_replication_slots - 启用
wal_compression减少网络传输 - 优化写入模式,减少大量小事务
- 使用连接池,减少连接开销
订阅者性能优化:
- 启用并行应用:调整
max_sync_workers_per_subscription - 确保订阅者有足够的 CPU 资源
- 使用高速存储设备(NVMe SSD)
- 定期执行
VACUUM ANALYZE优化查询计划 - 考虑使用
pg_prewarm预加载热点数据
网络优化:
- 使用高速网络连接
- 考虑压缩传输数据
- 避免跨地域长距离复制,或使用 CDN 加速
- 配置适当的 TCP 缓冲区大小
生产环境最佳实践
1. 设计与规划
发布/订阅架构设计:
- 单一发布者,多订阅者:适合数据分发场景
- 多发布者,单一订阅者:适合数据集成场景
- 分层发布:根据数据重要性创建不同的发布
- 订阅分组:将相关的发布分组到同一订阅
表设计最佳实践:
- 所有要复制的表必须有主键或唯一约束
- 添加
updated_at字段,便于冲突处理和数据追踪 - 避免使用不稳定的数据类型(如 TID)
- 考虑使用
rowversion列跟踪行版本 - 合理设计表结构,避免频繁的 schema 变更
2. 性能与可靠性
性能优化建议:
- 只复制必要的数据,减少网络流量
- 使用并行应用提高订阅者性能
- 合理设置复制槽保留策略
- 考虑使用多个订阅,分散复制负载
- 监控复制延迟,及时调整配置
可靠性建议:
- 定期备份发布者和订阅者数据
- 监控复制状态,设置告警阈值
- 配置适当的 WAL 保留策略
- 定期测试复制流程,确保数据一致性
- 准备灾难恢复计划
3. 安全与权限
安全最佳实践:
- 使用
scram-sha-256认证方式 - 严格限制复制用户的访问 IP 范围
- 启用 SSL/TLS 加密复制连接
- 定期轮换复制用户密码
- 遵循最小权限原则,只授予必要的权限
- 审计复制用户的活动
权限配置:
sql
-- 创建具有适当权限的复制用户
CREATE ROLE replicator WITH
REPLICATION
LOGIN
PASSWORD 'StrongPassword123!'
CONNECTION LIMIT 10;
-- 授予发布者权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO replicator;
-- 授予订阅者权限
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO replicator;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT INSERT, UPDATE, DELETE ON TABLES TO replicator;4. 监控与告警
核心监控指标:
| 指标类型 | 具体指标 | 告警阈值 |
|---|---|---|
| 复制状态 | 订阅状态 | 非 active 状态持续 > 5 分钟 |
| 复制延迟 | 应用延迟 | > 30 秒 |
| 冲突统计 | 冲突次数 | > 0 次/小时 |
| 复制槽 | 不活跃复制槽 | 持续 > 7 天 |
| 复制槽 | WAL 保留大小 | > 50 GB |
| 系统资源 | CPU 使用率 | > 80% 持续 > 5 分钟 |
| 系统资源 | 磁盘使用率 | > 90% |
告警渠道:
- 短信/电话告警:用于严重故障(复制中断、冲突过多)
- 邮件告警:用于普通告警(复制延迟、资源使用率高)
- 企业微信/钉钉告警:用于实时通知
5. 维护与管理
定期维护任务:
| 维护任务 | 频率 | 具体操作 |
|---|---|---|
| 复制状态检查 | 每日 | 检查所有订阅的状态和延迟 |
| 复制槽清理 | 每周 | 清理无效和不活跃的复制槽 |
| 数据一致性验证 | 每月 | 验证发布者和订阅者的数据一致性 |
| 性能评估 | 每季度 | 评估逻辑复制的性能,调整配置 |
| 备份验证 | 每半年 | 测试从备份恢复发布者和订阅者 |
| 灾难恢复演练 | 每年 | 进行完整的灾难恢复演练 |
变更管理:
表结构变更:
- 先在订阅者上创建兼容的表结构
- 在发布者上执行表结构变更
- 刷新订阅,获取最新的表结构
- 验证复制状态
发布/订阅变更:
- 提前规划变更,评估影响
- 在非高峰期执行变更
- 记录变更内容和时间
- 验证变更后的复制状态
6. 故障处理
常见故障及解决方案:
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 订阅状态为 down | 网络中断、发布者不可用 | 检查网络连接,重启订阅 |
| 复制延迟增加 | 订阅者资源不足、并行度不够 | 增加订阅者资源,调整并行工作进程数 |
| 复制冲突 | 订阅者上存在相同主键的行 | 调整冲突处理策略,手动修复冲突 |
| 复制槽堆积 | 订阅者长时间离线 | 清理无效复制槽,重新初始化订阅 |
| 订阅创建失败 | 表结构不兼容、权限不足 | 检查表结构和权限,重新创建订阅 |
| 数据不一致 | 初始同步失败、冲突未处理 | 重新初始化订阅,验证数据一致性 |
故障恢复流程:
- 故障检测:通过监控系统发现复制故障
- 故障诊断:查看日志和监控指标,确定故障原因
- 故障隔离:必要时禁用相关订阅,防止故障扩散
- 故障修复:根据故障类型采取相应的修复措施
- 恢复验证:验证复制状态和数据一致性
- 性能优化:分析故障原因,优化配置,防止类似故障再次发生
PostgreSQL 10-16 版本差异
PostgreSQL 10
- 引入基本的逻辑复制功能
- 支持表级复制
- 支持 INSERT、UPDATE、DELETE 操作
- 冲突处理能力有限
- 不支持并行应用
- 复制槽功能基础
PostgreSQL 11
- 增强了逻辑复制功能
- 支持发布级别的过滤
- 支持复制槽自动创建
- 增强了冲突处理
- 支持更多的发布选项
- 引入了复制原点功能
PostgreSQL 12
- 引入了逻辑复制的并行应用
- 支持更多的冲突处理策略
- 增强了逻辑复制的监控
- 优化了逻辑复制的性能
- 支持
pg_replication_origin功能 - 引入了
max_sync_workers_per_subscription参数
PostgreSQL 13
- 引入了逻辑复制的预写日志(WAL)优化
- 支持逻辑复制的双向复制
- 增强了逻辑复制的安全性
- 优化了逻辑复制的初始化过程
- 支持更多的数据类型复制
- 改进了复制槽管理
PostgreSQL 14
- 进一步优化了逻辑复制的性能
- 引入了
conflict_resolution参数,支持自动冲突处理 - 增强了逻辑复制的监控和统计信息
- 支持更多的发布和订阅选项
- 优化了大表的初始数据同步
- 改进了逻辑复制的错误处理
PostgreSQL 15
- 引入了发布级别的行过滤(WHERE 条件)
- 增强了逻辑复制的并行处理能力
- 优化了逻辑复制的冲突检测机制
- 支持更多的数据类型和操作
- 改进了复制槽的管理和监控
- 增强了逻辑复制的安全性
PostgreSQL 16
- 引入了 WAL 压缩算法选择
- 优化了逻辑复制的延迟计算
- 增强了级联逻辑复制支持
- 改进了复制槽自动清理机制
- 增强了逻辑复制的监控指标
- 优化了逻辑复制的内存管理
- 支持更多的表结构变更复制
总结
逻辑复制是 PostgreSQL 中一种灵活强大的复制机制,它基于发布/订阅模型,允许选择性地复制数据,支持跨版本、跨实例甚至跨数据库系统的复制。通过合理配置和管理逻辑复制,可以构建灵活可靠的数据复制架构,满足多种业务场景的需求。
在实际部署中,需要根据业务需求设计合适的发布/订阅架构,选择合适的冲突处理策略,并建立完善的监控和管理机制。同时,需要注意逻辑复制的性能和安全性,定期进行测试和维护,确保复制环境的可靠性和稳定性。
随着 PostgreSQL 版本的演进,逻辑复制功能不断增强,从基本的表级复制到支持并行应用、自动冲突处理和行级过滤,为 DBA 提供了越来越强大的数据复制工具。掌握逻辑复制的配置和管理,对于构建现代数据架构和确保数据库服务可靠性具有重要意义。
