Skip to content

PostgreSQL 半同步复制

核心概念

1. 什么是半同步复制

半同步复制是PostgreSQL的一种复制模式,结合了异步复制和同步复制的优点。主库在将WAL日志写入本地磁盘后,会等待一段时间,期望至少一个从库确认已接收WAL日志。如果在指定时间内收到确认,则按同步复制方式工作;如果超时未收到确认,则自动降级为异步复制。

2. 半同步复制的工作原理

  1. 主库执行事务提交,将WAL日志写入本地磁盘
  2. 主库等待从库确认已接收WAL日志(等待时间由参数控制)
  3. 从库接收WAL日志并写入磁盘,向主库发送确认
  4. 如果主库在超时前收到确认,向客户端返回成功
  5. 如果超时未收到确认,主库自动降级为异步复制,向客户端返回成功

3. 半同步复制的特点

优点

  • 数据安全性较高,大部分情况下无数据丢失
  • 主库性能优于完全同步复制
  • 自动故障降级,提高系统可用性
  • 配置灵活,可根据业务需求调整

缺点

  • 主库写入延迟比异步复制高
  • 仍存在极小概率的数据丢失风险(超时降级时)
  • 需要额外配置和维护

4. 与其他复制模式的比较

特性异步复制半同步复制同步复制
数据安全性较低较高极高
主库性能
配置复杂度简单中等复杂
适用场景性能优先平衡型安全优先

半同步复制配置

1. 安装半同步复制扩展

半同步复制需要安装PostgreSQL的扩展模块,该模块默认包含在PostgreSQL安装包中,但需要手动启用。

sql
-- 在主库上安装半同步复制扩展
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- 注意:PostgreSQL 9.6及以上版本,半同步复制扩展已内置,无需单独安装

2. 主库配置

bash
# 修改主库postgresql.conf
cat >> /var/lib/postgresql/15/main/postgresql.conf << EOF
# 启用半同步复制
# 主库发送端扩展
shared_preload_libraries = 'pgsync,pg_stat_statements'

# 启用半同步复制
wal_level = replica
max_wal_senders = 10

# 半同步复制配置
# 等待从库确认的超时时间(毫秒)
synchronous_commit = 'remote_write'
# 启用主库半同步发送
wal_sender_timeout = 60000
# 设置同步备用名称
# 注意:半同步复制仍需要配置synchronous_standby_names
# 但会在超时后自动降级为异步
EOF

# 重启主库使配置生效
pg_ctl restart -D /var/lib/postgresql/15/main

3. 从库配置

bash
# 修改从库postgresql.conf
cat >> /var/lib/postgresql/15/main/postgresql.conf << EOF
# 启用半同步复制接收端
shared_preload_libraries = 'pgsync,pg_stat_statements'

# 从库配置
hot_standby = on
max_standby_streaming_delay = 30s
hot_standby_feedback = on
EOF

# 重启从库使配置生效
pg_ctl restart -D /var/lib/postgresql/15/main

4. 启用半同步复制

sql
-- 在主库上启用半同步复制
ALTER SYSTEM SET synchronous_commit = 'remote_write';

-- 设置同步备用名称
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 ("standby1", "standby2")';

-- 应用配置
SELECT pg_reload_conf();

-- 验证半同步复制是否启用
SELECT name, setting FROM pg_settings WHERE name LIKE '%sync%';

半同步复制的高级配置

1. 调整同步提交级别

PostgreSQL支持多种同步提交级别,可以根据业务需求调整:

sql
-- 同步提交级别设置
-- local:只写入主库本地磁盘
-- remote_write:等待WAL写入从库操作系统缓冲区
-- remote_apply:等待WAL在从库应用完成
-- on:等待WAL写入从库磁盘(完全同步)

-- 半同步复制常用设置
ALTER SYSTEM SET synchronous_commit = 'remote_write';

-- 应用配置
SELECT pg_reload_conf();

2. 调整超时时间

sql
-- 调整半同步复制超时时间(毫秒)
-- 注意:PostgreSQL 10及以上版本,半同步复制超时由主库控制
-- 可以通过修改wal_sender_timeout参数调整
ALTER SYSTEM SET wal_sender_timeout = 30000;

-- 应用配置
SELECT pg_reload_conf();

3. 监控半同步复制状态

sql
-- 查看半同步复制状态
SELECT 
    name,
    setting,
    unit,
    short_desc
FROM pg_settings 
WHERE name IN (
    'synchronous_commit',
    'synchronous_standby_names',
    'wal_sender_timeout',
    'max_wal_senders'
);

-- 查看半同步复制统计信息
SELECT * FROM pg_stat_replication;

性能优化

1. 配置优化

bash
# 主库性能优化
cat >> /var/lib/postgresql/15/main/postgresql.conf << EOF
# 优化半同步复制性能
wal_writer_delay = 20ms
commit_delay = 10
commit_siblings = 5

# 增加WAL发送进程数
max_wal_senders = 10

# 优化检查点
checkpoint_timeout = 30min
max_wal_size = 4GB
checkpoint_completion_target = 0.9

# 启用WAL压缩
wal_compression = on
EOF

# 从库性能优化
cat >> /var/lib/postgresql/15/main/postgresql.conf << EOF
# 优化从库接收和应用WAL
max_worker_processes = 8
max_parallel_workers_per_gather = 4

# 优化从库查询性能
hot_standby = on
hot_standby_feedback = on
max_standby_streaming_delay = 30s
EOF

2. 网络优化

  • 使用专用网络连接主从库
  • 增加网络带宽
  • 优化网络路由,减少网络延迟
  • 考虑使用压缩传输(适用于远距离复制)

3. 硬件优化

  • 为主库配置高性能存储(如SSD)
  • 增加主库内存,减少磁盘I/O
  • 优化从库硬件,提高WAL接收和应用速度

监控与管理

1. 监控半同步复制状态

sql
-- 监控复制状态
SELECT 
    application_name,
    state,
    sync_state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    (sent_lsn - replay_lsn) AS replay_lag
FROM pg_stat_replication;

-- 监控半同步复制统计信息
SELECT * FROM pg_stat_replication;

-- 监控同步复制等待时间
SELECT 
    pid,
    state,
    wait_event,
    wait_event_type,
    query,
    now() - query_start AS query_duration
FROM pg_stat_activity
WHERE wait_event_type = 'Replication';

2. 监控半同步复制降级事件

sql
-- 查看数据库日志中的降级事件
-- 可以通过以下方式监控
SELECT * FROM pg_log WHERE message LIKE '%synchronous%' ORDER BY log_time DESC;

-- 或使用系统日志工具监控
# tail -f /var/log/postgresql/postgresql-15-main.log | grep -i sync

3. 常见问题处理

3.1 半同步复制频繁降级

问题现象:主库日志中频繁出现半同步复制降级为异步复制的消息

解决方法

sql
-- 1. 检查网络延迟
-- 在主库上测试网络延迟
# ping 从库IP
# traceroute 从库IP

-- 2. 调整超时时间
ALTER SYSTEM SET wal_sender_timeout = 60000;
SELECT pg_reload_conf();

-- 3. 优化从库性能
-- 增加从库的CPU和内存资源
-- 优化从库的WAL应用配置

-- 4. 检查从库状态
SELECT * FROM pg_stat_wal_receiver;

3.2 半同步复制不生效

问题现象:配置后半同步复制没有按预期工作

解决方法

sql
-- 1. 检查扩展是否正确加载
SELECT * FROM pg_extension WHERE extname LIKE '%sync%';

-- 2. 检查配置参数
SELECT name, setting FROM pg_settings WHERE name LIKE '%sync%';

-- 3. 检查同步备用名称配置
SHOW synchronous_standby_names;

-- 4. 检查从库应用名称是否匹配
SELECT application_name FROM pg_stat_replication;

3.3 主库写入延迟过高

问题现象:启用半同步复制后,主库写入延迟明显增加

解决方法

sql
-- 1. 调整同步提交级别
ALTER SYSTEM SET synchronous_commit = 'remote_write';
SELECT pg_reload_conf();

-- 2. 减少同步从库数量
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 ("standby1")';
SELECT pg_reload_conf();

-- 3. 优化网络和硬件
-- 使用专用网络连接
-- 增加网络带宽
-- 配置高性能存储

最佳实践

1. 配置最佳实践

  • 合理设置超时时间:根据网络延迟和业务需求调整超时时间,建议设置为500-2000毫秒
  • 选择合适的同步提交级别:根据业务对数据安全性的要求选择local、remote_write或remote_apply
  • 配置多个从库:配置2-3个从库,提高系统可用性和可靠性
  • 启用复制槽:防止WAL日志丢失,尤其是在半同步复制降级时
  • 定期检查复制状态:使用监控工具定期检查半同步复制状态,设置告警阈值

2. 运维最佳实践

  • 文档化配置:详细记录半同步复制的配置和管理流程
  • 定期备份:无论使用哪种复制模式,都要定期进行数据库备份
  • 测试故障切换:定期测试故障切换流程,确保在主库故障时能够快速恢复
  • 培训团队:确保运维团队熟悉半同步复制的管理和故障处理
  • 版本兼容性:确保主从库版本一致,或在支持的版本范围内

3. 业务场景最佳实践

业务场景推荐配置
电商交易系统synchronous_commit = 'remote_write', 超时时间 = 1000ms
金融核心系统synchronous_commit = 'on', 超时时间 = 2000ms
内容管理系统synchronous_commit = 'remote_write', 超时时间 = 500ms
日志分析系统建议使用异步复制

常见问题(FAQ)

Q1:半同步复制一定不会丢失数据吗?

A1:不是绝对的。在以下情况下仍可能丢失数据:

  • 主库等待从库确认超时,自动降级为异步复制时
  • 主库在收到从库确认前崩溃,但从库尚未写入WAL日志到磁盘
  • 网络分区导致主库无法收到从库确认,自动降级为异步复制

Q2:如何选择半同步复制的超时时间?

A2:超时时间的选择取决于:

  • 主从库之间的网络延迟
  • 业务对写入延迟的容忍度
  • 业务对数据安全性的要求

建议根据实际测试结果调整,一般设置为网络延迟的2-3倍,通常在500-2000毫秒之间。

Q3:半同步复制支持多个从库吗?

A3:是的,半同步复制支持配置多个从库,可以通过synchronous_standby_names参数指定:

sql
-- 等待任意1个从库确认
ALTER SYSTEM SET synchronous_standby_names = 'ANY 1 ("standby1", "standby2", "standby3")';
SELECT pg_reload_conf();

Q4:如何监控半同步复制的性能?

A4:可以通过以下方式监控:

sql
-- 监控主库写入等待时间
SELECT 
    pid,
    state,
    wait_event,
    wait_event_type,
    query,
    now() - query_start AS query_duration
FROM pg_stat_activity
WHERE wait_event_type = 'Replication';

-- 监控复制延迟
SELECT 
    application_name,
    sync_state,
    (sent_lsn - replay_lsn) AS replay_lag
FROM pg_stat_replication;

Q5:半同步复制和同步复制可以同时使用吗?

A5:可以。PostgreSQL支持在同一个集群中混合使用不同的复制模式,通过synchronous_commit参数可以为不同的会话或事务设置不同的同步级别。

Q6:如何从半同步复制切换到其他复制模式?

A6:可以通过修改synchronous_commit参数切换:

sql
-- 切换到异步复制
ALTER SYSTEM SET synchronous_commit = 'local';
SELECT pg_reload_conf();

-- 切换到完全同步复制
ALTER SYSTEM SET synchronous_commit = 'on';
SELECT pg_reload_conf();

Q7:半同步复制需要额外的许可证吗?

A7:不需要。半同步复制是PostgreSQL的内置功能,包含在开源版本中,无需额外购买许可证。

Q8:半同步复制适用于所有版本的PostgreSQL吗?

A8:半同步复制从PostgreSQL 9.1版本开始引入,不同版本的功能和配置方式可能有所不同。建议使用PostgreSQL 9.6及以上版本,这些版本的半同步复制功能更加稳定和完善。

半同步复制的应用场景

  1. 电商交易系统:需要较高的数据安全性,同时对性能有一定要求
  2. 金融支付系统:要求高数据安全性,可接受一定的性能损失
  3. 医疗数据系统:对数据安全性要求高,需要平衡性能
  4. 政府政务系统:要求数据安全性,同时需要系统高可用
  5. 混合业务场景:部分业务要求高安全性,部分业务要求高性能

半同步复制是一种灵活的复制模式,能够在数据安全性和性能之间取得良好的平衡,适用于大多数企业级应用场景。