Skip to content

PostgreSQL 多活架构设计

核心概念

多活架构是指多个数据库节点同时对外提供读写服务,实现数据的双向或多向同步,提高系统的可用性和容灾能力。PostgreSQL多活架构主要涉及以下核心概念:

  • 双向复制:两个或多个节点之间实现数据的相互同步
  • 冲突处理:解决多个节点同时修改同一数据时产生的冲突
  • 数据一致性:确保多个节点之间的数据最终一致
  • 故障自动切换:当某个节点故障时,自动将流量切换到其他节点
  • 地理分布式部署:将节点部署在不同地理位置,提高容灾能力

多活架构设计模式

1. 双向逻辑复制模式

利用PostgreSQL内置的逻辑复制功能,实现两个或多个节点之间的双向数据同步。

适用场景

  • 跨区域容灾
  • 读写分离扩展
  • 应用就近访问

2. 基于中间件的多活模式

通过中间件(如Pgpool-II、Bucardo等)管理多个PostgreSQL节点,实现数据同步和请求路由。

适用场景

  • 复杂拓扑结构
  • 需要中间层进行冲突处理
  • 已有中间件基础设施

3. 基于分片的多活模式

将数据分片存储在不同节点,每个分片可以有多个副本,实现分片级别的多活。

适用场景

  • 超大规模数据量
  • 高并发写入场景
  • 需要线性扩展能力

配置方法

1. 双向逻辑复制配置

节点A(主节点1)配置

sql
-- 启用逻辑复制
ALTER SYSTEM SET wal_level = 'logical';
ALTER SYSTEM SET max_replication_slots = 10;
ALTER SYSTEM SET max_wal_senders = 10;

-- 重启数据库使配置生效
-- sudo systemctl restart postgresql-15

-- 创建复制用户
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'repl_password';

-- 创建发布
CREATE PUBLICATION pub_node_a FOR ALL TABLES;

节点B(主节点2)配置

sql
-- 启用逻辑复制(同节点A)
ALTER SYSTEM SET wal_level = 'logical';
ALTER SYSTEM SET max_replication_slots = 10;
ALTER SYSTEM SET max_wal_senders = 10;

-- 重启数据库使配置生效

-- 创建复制用户
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'repl_password';

-- 创建发布
CREATE PUBLICATION pub_node_b FOR ALL TABLES;

-- 创建订阅(订阅节点A的发布)
CREATE SUBSCRIPTION sub_node_a
  CONNECTION 'host=node_a_host port=5432 dbname=postgres user=repl password=repl_password'
  PUBLICATION pub_node_a;

节点A配置订阅节点B

sql
-- 创建订阅(订阅节点B的发布)
CREATE SUBSCRIPTION sub_node_b
  CONNECTION 'host=node_b_host port=5432 dbname=postgres user=repl password=repl_password'
  PUBLICATION pub_node_b;

2. Bucardo多活配置

安装Bucardo

bash
# 在CentOS/RHEL上安装
sudo yum install -y bucardo

# 在Ubuntu/Debian上安装
sudo apt-get install -y bucardo

配置Bucardo

bash
# 初始化Bucardo
sudo su - postgres -c "bucardo_ctl init"

# 添加数据库
 b) sudo su - postgres -c "bucardo_ctl add db db1 dbname=postgres host=node1 user=bucardo password=bucardo"
 sudo su - postgres -c "bucardo_ctl add db db2 dbname=postgres host=node2 user=bucardo password=bucardo"

# 添加表
 sudo su - postgres -c "bucardo_ctl add table all"  

# 创建同步组
 sudo su - postgres -c "bucardo_ctl add sync mysync dbs=db1,db2 tables=all conflict_strategy=latest"

# 启动Bucardo
 sudo su - postgres -c "bucardo_ctl start"

冲突处理机制

1. 冲突类型

  • 插入冲突:多个节点同时插入具有相同主键的数据
  • 更新冲突:多个节点同时更新同一行数据
  • 删除冲突:一个节点删除数据,另一个节点更新该数据

2. 冲突处理策略

基于时间戳的冲突解决

sql
-- 在表中添加时间戳字段
ALTER TABLE table_name ADD COLUMN last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW();

-- 创建触发器,自动更新时间戳
CREATE OR REPLACE FUNCTION update_last_updated()
RETURNS TRIGGER AS $$
BEGIN
    NEW.last_updated = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_last_updated_trigger
BEFORE UPDATE ON table_name
FOR EACH ROW
EXECUTE FUNCTION update_last_updated();

基于优先级的冲突解决

在中间件层或应用层设置节点优先级,当发生冲突时,高优先级节点的数据获胜。

基于应用逻辑的冲突解决

在应用层面实现冲突检测和解决逻辑,例如:

  • 使用业务规则判断冲突数据的有效性
  • 发送告警通知管理员手动处理
  • 回滚冲突事务并重新执行

性能优化

1. 复制性能优化

sql
-- 调整WAL发送缓冲区大小
ALTER SYSTEM SET wal_sender_buffer_size = '64MB';

-- 调整逻辑复制槽大小
ALTER SYSTEM SET max_slot_wal_keep_size = '1GB';

-- 启用并行应用(PostgreSQL 14+)
ALTER SUBSCRIPTION sub_name SET (parallel_apply = 4);

2. 冲突避免优化

  • 数据分片:将数据按照业务规则分片,避免同一数据在多个节点同时被修改
  • 应用设计:设计应用时避免多个节点同时修改同一数据
  • 事务设计:缩短事务时间,减少冲突窗口
  • 批量操作:将频繁的小更新合并为批量操作

3. 监控优化

sql
-- 监控复制延迟
SELECT 
    slot_name,
    pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) AS replication_lag_bytes
FROM pg_replication_slots;

-- 监控订阅状态
SELECT * FROM pg_stat_subscription;

监控与管理

1. 复制状态监控

  • 内置视图:使用pg_stat_replicationpg_stat_subscriptionpg_replication_slots等视图监控复制状态
  • 日志监控:监控PostgreSQL日志中的复制相关信息
  • 第三方工具:使用Prometheus + Grafana、Zabbix等工具监控复制状态

2. 冲突监控

  • PostgreSQL日志:查看日志中的冲突信息
  • Bucardo日志:如果使用Bucardo,查看Bucardo日志中的冲突记录
  • 自定义监控:在应用层实现冲突计数和告警

3. 故障处理

节点故障处理流程

  1. 检测节点故障(通过心跳检测或监控系统)
  2. 确认故障节点状态
  3. 停止向故障节点发送请求
  4. 等待数据同步完成
  5. 恢复故障节点
  6. 重新加入集群

最佳实践

1. 架构设计最佳实践

  • 节点数量:建议多活节点数量不超过4个,避免过于复杂的复制拓扑
  • 地理分布:将节点部署在不同可用区或地域,提高容灾能力
  • 网络规划:确保节点之间网络延迟低、带宽充足
  • 硬件配置:所有节点使用相同或相似的硬件配置,避免性能差异

2. 配置最佳实践

  • WAL级别:使用logical级别,支持逻辑复制
  • 复制槽:为每个订阅创建单独的复制槽
  • 连接数:合理设置max_connections,预留足够连接给复制进程
  • 内存配置:为复制进程分配足够的内存资源

3. 运维最佳实践

  • 定期备份:即使是多活架构,也要定期进行数据库备份
  • 演练:定期进行故障切换演练,确保故障处理流程有效
  • 监控:建立完善的监控体系,及时发现和处理问题
  • 文档:详细记录架构设计、配置参数和运维流程

常见问题(FAQ)

Q1:多活架构中如何处理大事务?

A1:大事务会增加复制延迟和冲突风险,建议:

  1. 将大事务拆分为多个小事务
  2. 在低峰期执行大事务
  3. 调整max_wal_size等参数,优化大事务处理
  4. 监控大事务对复制延迟的影响

Q2:如何选择合适的多活架构模式?

A2:根据业务需求和技术栈选择:

  1. 小规模部署:推荐使用双向逻辑复制
  2. 复杂拓扑:推荐使用基于中间件的多活模式
  3. 超大规模数据:推荐使用基于分片的多活模式

Q3:多活架构的性能开销有多大?

A3:多活架构的性能开销主要包括:

  1. 复制开销:约10%-30%的额外CPU和IO开销
  2. 冲突处理开销:根据冲突频率而定
  3. 监控开销:额外的监控进程资源消耗

Q4:如何确保多活架构的数据一致性?

A4:确保数据一致性的方法:

  1. 使用可靠的复制技术
  2. 实现有效的冲突处理机制
  3. 建立完善的监控体系
  4. 定期进行数据一致性检查

Q5:多活架构与主从架构相比有什么优势?

A5:多活架构的优势:

  1. 更高的可用性:多个节点同时提供服务,单个节点故障不影响整体可用性
  2. 更好的性能:可以实现负载均衡,提高整体吞吐量
  3. 更强的容灾能力:节点分布在不同地理位置,抗灾难能力更强
  4. 更好的扩展性:可以通过增加节点线性扩展系统容量