外观
PostgreSQL 从单机到集群
随着业务的发展,单机 PostgreSQL 数据库可能无法满足日益增长的性能和可用性需求。将单机数据库迁移到集群架构是提高系统可用性、性能和可扩展性的重要手段。本文将详细介绍 PostgreSQL 从单机到集群的迁移过程、架构选择、实施步骤和最佳实践。
集群架构选择
1. 主从复制架构
特点:
- 一主多从架构,主库负责读写,从库负责只读查询
- 基于 WAL 日志的异步或同步复制
- 从库可用于故障转移和读写分离
- 实现简单,维护成本低
适用场景:
- 提高读性能(通过读写分离)
- 提高可用性(通过故障转移)
- 数据备份和灾备
2. 流式复制集群
特点:
- 基于 PostgreSQL 内置的流复制机制
- 支持同步复制和异步复制
- 可配合第三方工具实现自动故障转移
- 支持级联复制(从库作为其他从库的主库)
适用场景:
- 高可用性要求较高的场景
- 数据一致性要求较高的场景
- 需要自动故障转移的场景
3. 逻辑复制集群
特点:
- 基于 PostgreSQL 10+ 内置的逻辑复制机制
- 支持表级复制和选择性复制
- 支持跨版本复制
- 支持多主复制(通过双向逻辑复制)
适用场景:
- 需要选择性复制的场景
- 跨版本复制场景
- 多主复制场景
- 数据分片场景
4. 分片集群
特点:
- 将数据分散存储在多个节点上
- 每个节点只存储部分数据
- 支持水平扩展
- 需要中间件或扩展支持
适用场景:
- 超大数据量场景(TB 或 PB 级别)
- 高并发写入场景
- 需要水平扩展的场景
5. 常用集群解决方案
| 解决方案 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| PostgreSQL 原生流复制 | 主从复制 | 官方支持,实现简单 | 基本高可用性需求 |
| Patroni + etcd | 高可用集群 | 自动故障转移,负载均衡 | 企业级高可用性需求 |
| pgpool-II | 中间件 | 负载均衡,连接池,故障转移 | 读写分离,负载均衡需求 |
| Citus | 分片集群 | 水平扩展,分布式查询 | 超大数据量,高并发需求 |
| TimescaleDB | 时序集群 | 时序数据优化,水平扩展 | 时序数据场景 |
迁移前准备
环境准备
源环境检查:
sql-- 检查源数据库版本 SELECT version(); -- 检查数据库大小 SELECT datname, pg_database_size(datname) / 1024 / 1024 AS size_mb FROM pg_database; -- 检查WAL配置 SHOW wal_level; SHOW archive_mode; SHOW archive_command;目标环境准备:
- 准备至少3台服务器(1主2从或3主)
- 安装与源数据库版本相同的 PostgreSQL
- 配置相同的参数(postgresql.conf、pg_hba.conf等)
- 配置服务器之间的SSH免密登录
- 配置防火墙规则,允许服务器之间的通信
备份准备
全量备份:对源数据库进行全量备份,确保数据安全
bashpg_basebackup -h source_host -p 5432 -U repl -D /path/to/backup -F t -z -P增量备份:确保WAL日志正常归档,以便进行增量恢复
sql-- 启用WAL归档 ALTER SYSTEM SET archive_mode = on; ALTER SYSTEM SET archive_command = 'cp %p /path/to/archive/%f'; SELECT pg_reload_conf();
架构设计
- 确定集群规模:根据业务需求确定主从节点数量
- 确定复制类型:选择同步复制或异步复制
- 确定故障转移机制:选择手动故障转移或自动故障转移
- 确定负载均衡方案:选择内置负载均衡或第三方负载均衡
- 确定监控方案:选择内置监控或第三方监控
迁移步骤
1. 搭建主从复制集群
步骤1:配置主库
修改 postgresql.conf:
ini# 启用流复制 wal_level = replica max_wal_senders = 10 wal_keep_size = 1GB max_replication_slots = 10 # 启用归档(可选) archive_mode = on archive_command = 'cp %p /path/to/archive/%f'修改 pg_hba.conf:
ini# 允许从库连接 host replication repl 192.168.1.0/24 md5创建复制用户:
sqlCREATE USER repl REPLICATION LOGIN ENCRYPTED PASSWORD 'repl_password';重启主库:
bashpg_ctl -D /path/to/data restart
步骤2:配置从库
清空从库数据目录:
bashrm -rf /path/to/data/*从主库同步数据:
bashpg_basebackup -h master_host -p 5432 -U repl -D /path/to/data -F p -X stream -P -R修改 postgresql.conf(可选,针对从库的特定配置):
ini# 从库特定配置 hot_standby = on max_standby_streaming_delay = 30s wal_receiver_status_interval = 10s hot_standby_feedback = on启动从库:
bashpg_ctl -D /path/to/data start验证复制状态:
sql-- 在主库上检查 SELECT * FROM pg_stat_replication; -- 在从库上检查 SELECT pg_is_in_recovery(); SELECT * FROM pg_stat_wal_receiver;
2. 配置负载均衡
使用 pgpool-II 配置负载均衡
安装 pgpool-II:
bash# CentOS/RHEL yum install pgpool-II-pg14 # Ubuntu/Debian apt-get install pgpool2配置 pgpool.conf:
ini# 启用负载均衡 load_balance_mode = on # 配置主从节点 backend_hostname0 = 'master_host' backend_port0 = 5432 backend_weight0 = 1 backend_flag0 = 'ALLOW_TO_FAILOVER' backend_hostname1 = 'slave1_host' backend_port1 = 5432 backend_weight1 = 1 backend_flag1 = 'ALLOW_TO_FAILOVER' backend_hostname2 = 'slave2_host' backend_port2 = 5432 backend_weight2 = 1 backend_flag2 = 'ALLOW_TO_FAILOVER' # 配置健康检查 health_check_period = 5 health_check_timeout = 20 health_check_user = 'postgres' health_check_password = 'password'配置 pcp.conf:
ini# 用于 PCP 管理的用户和密码 postgres:md5password启动 pgpool-II:
bashsystemctl start pgpool-II验证负载均衡:
bash# 连接到 pgpool-II psql -h pgpool_host -p 9999 -U postgres -c "SELECT current_user, inet_client_addr();"
3. 配置自动故障转移
使用 Patroni 配置自动故障转移
安装 Patroni 和 etcd:
bash# 安装 Patroni pip install patroni[etcd] # 安装 etcd(用于存储集群状态) yum install etcd配置 etcd:
yaml# /etc/etcd/etcd.conf ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://etcd_host:2380" ETCD_ADVERTISE_CLIENT_URLS="http://etcd_host:2379" ETCD_INITIAL_CLUSTER="etcd1=http://etcd_host:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-1" ETCD_INITIAL_CLUSTER_STATE="new" ETCD_NAME="etcd1"配置 Patroni:
yaml# patroni.yml scope: postgres_cluster namespace: /db/ name: postgres1 restapi: listen: postgres1:8008 connect_address: postgres1:8008 etcd: hosts: etcd_host:2379 bootstrap: dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 postgresql: use_pg_rewind: true use_slots: true parameters: listen_addresses: "'*'" max_connections: 100 wal_level: replica hot_standby: on logging_collector: on log_directory: 'pg_log' log_filename: 'postgresql-%Y-%m-%d_%H%M%S.log' log_truncate_on_rotation: true log_rotation_age: 1d log_rotation_size: 0 max_wal_senders: 10 max_replication_slots: 10 wal_keep_size: 1GB archive_mode: on archive_command: '/bin/true' initdb: - encoding: UTF8 - data-checksums pg_hba: - host replication replicator 127.0.0.1/32 md5 - host replication replicator postgres0/32 md5 - host replication replicator postgres1/32 md5 - host replication replicator postgres2/32 md5 - host all all 0.0.0.0/0 md5 users: admin: password: admin_password options: - createrole - createdb postgresql: listen: postgres1:5432 connect_address: postgres1:5432 data_dir: /data/patroni bin_dir: /usr/pgsql-14/bin pgpass: /tmp/pgpass0 authentication: replication: username: replicator password: replication_password superuser: username: postgres password: postgres_password parameters: unix_socket_directories: '/tmp' tags: nofailover: false noloadbalance: false clonefrom: false nosync: false启动 Patroni:
bashpatroni patroni.yml验证集群状态:
bash# 使用 patronictl 查看集群状态 patronictl -c patroni.yml list
4. 数据迁移
方法1:使用 pg_basebackup 进行初始同步
在主库上执行 pg_basebackup:
bashpg_basebackup -h master_host -p 5432 -U repl -D /path/to/data -F p -X stream -P -R启动从库:
bashpg_ctl -D /path/to/data start验证复制状态:
sqlSELECT * FROM pg_stat_replication;
方法2:使用逻辑复制进行数据同步
在主库上创建发布:
sqlCREATE PUBLICATION my_publication FOR ALL TABLES;在从库上创建订阅:
sqlCREATE SUBSCRIPTION my_subscription CONNECTION 'host=master_host port=5432 dbname=dbname user=repl password=repl_password' PUBLICATION my_publication;验证复制状态:
sqlSELECT * FROM pg_stat_subscription;
5. 应用切换
更新应用连接配置:
- 将应用连接从单机数据库切换到集群的负载均衡地址
- 更新连接池配置
测试应用连接:
bashpsql -h cluster_host -p 9999 -U app_user -d app_db -c "SELECT 1;"监控应用性能:
- 监控应用响应时间
- 监控数据库连接数
- 监控查询性能
6. 迁移后验证
检查集群状态:
sql-- 检查主从状态 SELECT * FROM pg_stat_replication; -- 检查从库状态 SELECT pg_is_in_recovery();检查数据一致性:
sql-- 在主库上执行 CREATE TABLE test_consistency (id serial PRIMARY KEY, value text); INSERT INTO test_consistency (value) VALUES ('test'); -- 在从库上检查 SELECT * FROM test_consistency;测试故障转移:
bash# 手动触发故障转移 patronictl -c patroni.yml failover # 或停止主库服务模拟故障 pg_ctl -D /path/to/master/data stop -m fast测试负载均衡:
bash# 多次连接,检查是否分发到不同节点 for i in {1..10}; do psql -h cluster_host -p 9999 -U postgres -c "SELECT inet_client_addr();" done
最佳实践
1. 集群设计最佳实践
- 合理规划节点数量:根据业务需求和预算确定节点数量,一般建议至少3个节点(1主2从)
- 选择合适的复制类型:对数据一致性要求高的场景选择同步复制,对性能要求高的场景选择异步复制
- 实现自动故障转移:使用 Patroni、pgpool-II 等工具实现自动故障转移,减少人工干预
- 配置负载均衡:使用负载均衡分发读写请求,提高系统性能和可用性
- 实现监控和告警:配置监控系统,实时监控集群状态和性能
2. 性能优化最佳实践
- 优化复制配置:根据业务需求调整 wal_keep_size、max_wal_senders 等参数
- 使用连接池:使用 PgBouncer 或 pgpool-II 等连接池工具,减少数据库连接数
- 实现读写分离:将只读请求分发到从库,提高系统整体性能
- 优化查询:优化慢查询,减少数据库负载
- 合理设置索引:根据查询需求合理设置索引,提高查询性能
3. 可用性优化最佳实践
- 实现多级备份:定期进行全量备份和增量备份,确保数据安全
- 配置 WAL 归档:启用 WAL 归档,确保可以进行 Point-in-Time Recovery (PITR)
- 实现灾备机制:在不同地域部署从库,实现异地灾备
- 定期进行故障演练:定期模拟故障,测试故障转移机制的有效性
- 制定应急预案:制定详细的应急预案,确保在故障发生时能够快速响应
4. 维护最佳实践
- 定期更新 PostgreSQL 版本:及时更新到最新的稳定版本,获取新功能和安全补丁
- 定期更新集群软件:及时更新 Patroni、pgpool-II 等集群软件
- 定期进行健康检查:定期检查集群节点的健康状态
- 定期清理 WAL 日志:定期清理过期的 WAL 日志,释放磁盘空间
- 定期更新统计信息:定期运行 ANALYZE,更新统计信息,提高查询优化器的准确性
案例分析
案例1:电商系统从单机到主从集群
背景:某电商系统使用单机 PostgreSQL 13 数据库,随着业务增长,读请求量急剧增加,需要提高系统的读性能和可用性。
解决方案:
- 搭建 1 主 2 从的流复制集群
- 使用 pgpool-II 实现负载均衡和读写分离
- 使用 Patroni 实现自动故障转移
- 将应用连接指向 pgpool-II 地址
实施步骤:
- 搭建主从复制:配置主库的流复制参数,初始化从库,验证复制状态
- 配置 pgpool-II:配置负载均衡和读写分离,启动 pgpool-II 服务
- 配置 Patroni:配置自动故障转移,启动 Patroni 服务
- 应用切换:将应用连接从单机数据库切换到 pgpool-II 地址
- 验证集群:测试负载均衡、故障转移和数据一致性
实施效果:
- 读性能提升 200%(通过 2 个从库分担读请求)
- 可用性提高到 99.99%(通过自动故障转移)
- 系统可以承受单个节点故障,不会影响业务
案例2:金融系统从单机到高可用集群
背景:某金融系统使用单机 PostgreSQL 12 数据库,对数据一致性和可用性要求极高,需要实现零数据丢失和自动故障转移。
解决方案:
- 搭建 1 主 2 从的同步复制集群
- 使用 Patroni + etcd 实现自动故障转移
- 配置 WAL 归档和 PITR 恢复机制
- 实现异地灾备(在不同地域部署从库)
实施步骤:
- 搭建同步复制集群:配置主库的同步复制参数,初始化从库,验证复制状态
- 配置 WAL 归档:启用 WAL 归档,配置归档命令
- 配置 Patroni:配置自动故障转移,启动 Patroni 服务
- 配置异地灾备:在异地部署从库,配置异步复制
- 应用切换:将应用连接指向集群主库地址
- 验证集群:测试同步复制、故障转移和数据一致性
实施效果:
- 数据零丢失(通过同步复制)
- 可用性提高到 99.999%(通过自动故障转移和异地灾备)
- 系统可以承受多节点故障,不会影响业务
- 支持 PITR 恢复,可以恢复到任意时间点
总结
将 PostgreSQL 从单机迁移到集群是提高系统可用性、性能和可扩展性的重要手段。在迁移过程中,需要选择合适的集群架构,搭建主从复制,配置负载均衡和故障转移机制,进行数据迁移和应用切换,并进行全面的验证。
通过合理的集群设计、性能优化和可用性优化,可以构建高可用、高性能的 PostgreSQL 集群,满足日益增长的业务需求。同时,定期进行维护和故障演练,确保集群的长期稳定运行。
本文介绍了 PostgreSQL 从单机到集群的迁移过程、架构选择、实施步骤和最佳实践,希望能帮助 DBA 们顺利完成从单机到集群的迁移,构建高可用、高性能的 PostgreSQL 集群。
