广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

技术负责人 | PG并发控制:集群搭建教程

PG并发控制在集群搭建中是容易出幺蛾子的地方。我见过不少团队在部署主从复制时,因为没正确设置max_connections导致集群崩溃。真实场景里,主节点的并发数通常要留10%-20%余量,用来处理写入流量。主从同步时,从节点的fetch_max_block_size参数调大后,sync_commit参数必须同步调整,否则会引发大量延迟。

技术负责人 | PG并发控制:集群搭建教程
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
PG并发控制在集群搭建中是容易出幺蛾子的地方。我见过不少团队在部署主从复制时,因为没正确设置max_connections导致集群崩溃。真实场景里,主节点的并发数通常要留10%-20%余量,用来处理写入流量。主从同步时,从节点的fetch_max_block_size参数调大后,sync_commit参数必须同步调整,否则会引发大量延迟。在实际搭建中,使用pg_rewind来修复主从数据偏移,比pg_basebackup更稳定,但要确保主从日志没有被删除。我用过的工具里,Patroni配合etcd在高可用场景下表现不错,但需要配置好health_check_period和health_check_timeout,否则会频繁触发切换。部署时,别忘了在共享内存参数里调整shared_buffers和effective_cache_size,这两个参数直接影响并发性能。

▌ 技术参考

一 如今的PG集群搭建多数会通过Patroni配合etcd来实现高可用,这种组合在2024-2026年的生产环境里被广泛采用。Patroni的核心是通过etcd保持状态一致性,确保主节点选举和故障转移的可靠性。实际部署时,etcd的集群规模最好是3节点,避免单点故障。Patroni配置文件通常放在/etc/patroni.d/dummy.yml,关键配置项包括etcd_url、cluster_name、restapi_listeners。在节点初始化时,必须使用patroni init来创建etcd的初始值,否则集群会处于等待状态。如果某个节点无法加入集群,可以通过etcdctl检查节点是否被正确注册,并确保每个节点的etcd_key_prefix是唯一的。

二 配置主从复制时,最重要的参数是max_connections。主节点的max_connections通常是集群中所有节点总数的1.2倍,比如三个节点的话,主节点设为150,从节点设为100。这个经验值来自我在2025年参与的某个云计算平台项目,当时主节点设置不当导致写入队列溢出。另外,主节点的shared_buffers建议设为物理内存的25%,从节点可以设为物理内存的40%。使用pg_rewind进行数据恢复时,必须确保主从之间的wal_level是hot_standby,否则会报错。配置文件中需要设置wal_level=hot_standby,并且主节点必须启用track_activity_query和track_commit_timestamp,以便pg_rewind能正确识别数据差异。

三 在部署Patroni集群时,节点的初始化顺序非常关键。先创建etcd集群,再执行patroni init命令,这样可以避免节点因为找不到etcd实例而挂起。如果多个节点同时初始化,可能会导致etcd集群状态混乱。在etcd配置文件中,需要指定advertise-client-urls和initial-cluster参数,确保所有节点都能互相通信。Patroni的监控系统通过restapi来暴露状态,因此必须配置restapi_listeners,比如监听本地端口8008。同时,健康检查间隔health_check_period设置为10秒比较合理,health_check_timeout设为5秒防止误判。如果health_check_period太小,会导致频繁切换,增加系统压力。

四 日志配置是集群稳定性的重要保障。在2026年某次高并发测试中,因为未正确设置log_line_prefix,导致无法快速定位锁冲突问题。建议将log_line_prefix设为包含%u、%x、%l、%r等参数,以便记录用户、事务ID、锁类型等关键信息。log_min_duration_statement设为500ms有助于捕捉长查询,这对排查锁等待问题很有帮助。在日志存储方面,可以结合logrotate进行管理,避免磁盘空间不足。配置logrotate时,注意保留最近7天的日志,同时设置压缩选项。如果集群规模大,建议将日志分为主从节点各自存储,减少单点压力。

五 主从同步延迟是很多团队头疼的问题,尤其是在写入密集型业务场景。我曾使用pg_basebackup进行冷备份,但发现同步延迟很高,后来改用streaming replication配合wal_level=logical,延迟显著降低。在从节点启动时,需要指定primary_conninfo参数,包括host、port和user,例如primary_conninfo='host=192.168.1.10 port=5432 user=repl password=secret'。如果从节点频繁出现断连,可以检查pg_hba.conf配置是否允许远程连接,同时确保SSL配置正确。在从节点上启用log_min_duration_statement=0,记录所有事务日志,方便后续分析。

六 在集群搭建中,pg_rewind是修复主从偏移的利器,但必须在特定条件下使用。比如主节点宕机后,从节点需要同步到最新状态,此时使用pg_rewind比pg_basebackup更高效。不过,pg_rewind要求主节点和从节点的wal_level必须是hot_standby,并且主节点上的pg_rewind必须存在。实际操作时,先在从节点上停止复制,执行pg_rewind命令,并指定主节点的数据库连接信息。例如:pg_rewind --target-pgid=12345 --source-server="host=192.168.1.10 port=5432 user=repl password=secret"。完成后,重新启动复制进程,并检查wal_replay_pause是否启用,防止数据冲突。

七 集群的监控和告警配置不能忽视,特别是在2024年之后的架构演进中,很多团队开始使用Prometheus + Grafana来监控PG状态。Prometheus的配置文件需要包含pg_stat_statements、pg_stat_activity、pg_stat_wal_receiver等指标。在Grafana中,建议设置监控指标包括replication lag、active transactions、lock wait time等。如果发现某个从节点的replication lag超过10分钟,必须立即排查网络、磁盘I/O或主节点压力问题。在告警规则中,可以设置阈值,比如当replication lag > 30秒时触发告警,这在2026年的实际生产中已经很常见。

八 在使用Patroni时,如果遇到主节点频繁切换,应该检查health_check_period和health_check_timeout的配置。这两个参数如果设置不当,会导致不必要的故障转移。例如,health_check_period设为3秒,health_check_timeout设为1秒,这会引发误判。建议将health_check_period设为10秒,health_check_timeout设为5秒。此外,需要确保每个节点的健康检查脚本是可靠的,避免因为脚本错误导致状态异常。在健康检查脚本中,通常会执行SELECT 1 FROM pg_sleep(1)来测试连接,如果返回失败则认为节点不健康。这个脚本必须有权限访问数据库,并且在集群所有节点上保持一致。

九 集群的拓扑结构对并发控制起着决定性作用,尤其是在使用流复制的情况下。主节点需要处理所有写入请求,而从节点只负责读取和同步。在2025年我负责的某金融系统项目中,因为从节点数量不足,导致主节点负载过高,最终引发连接超时。建议主节点配置至少两个从节点,这样可以分散读取压力。在使用Patroni时,需要配置followers_limit参数来限制从节点数量,避免资源浪费。同时,要确保主节点的replication_max_connections参数足够大,否则会限制从节点连接数,影响同步效率。

十 在高并发场景下,使用pg_rewind比传统的pg_basebackup更高效,但需要确保主从节点的WAL日志没有被清除。如果主节点的archive_mode关闭,或者wal_keep_segments设置过低,pg_rewind可能无法找到足够的日志进行修复。在2026年的一个项目中,因为未正确设置wal_keep_segments=100,导致pg_rewind丢失日志,最终不得不使用pg_basebackup重新同步,耗时接近3小时。建议在主节点上设置wal_keep_segments至少为集群中最大可能的复制延迟乘以10。同时,确保archive_mode开启,并且archive_command正确指向归档目录,例如archive_command='cp %p /archive/%f'。

十一 集群的分区策略对并发控制有直接影响。例如在使用表分区时,如果未正确配置分区索引和锁机制,可能会导致锁冲突。我曾在一个电商系统中遇到这样的问题,某个订单表按时间分区后,由于未使用row-level locking,导致多个事务同时修改同一分区时发生死锁。解决办法是使用SET LOCAL lock_timeout=10000来设置事务等待时间,同时在DDL操作时使用LOCK TABLE来控制锁粒度。此外,分区表的每个子表都应配置独立的复制槽,防止复制槽资源耗尽影响同步效率。

十二 在使用Patroni进行高可用部署时,需要确保所有节点的配置文件一致,否则可能导致选举失败。例如,一个节点的etcd_url写错,会导致它无法参与集群状态管理,从而成为孤立节点。配置文件中设置的cluster_name必须统一,否则节点无法识别彼此。在2026年初,某次集群部署失败是因为某个节点的cluster_name拼写错误,导致整个集群状态混乱。建议在部署时使用Ansible或Terraform统一配置,避免人为疏忽。同时,Patroni的conf_file可以指定为/etc/patroni.yml,确保每个节点都使用相同的配置。

十三 集群的并发控制不仅依赖于参数配置,还与数据库事务的隔离级别密切相关。在使用READ COMMITTED隔离级别时,LOCK和SELECT语句的行为会显著影响性能。例如,在一个高并发的报表系统中,由于未正确使用SET LOCAL isolation_level=READ UNCOMMITTED,导致大量锁等待,最终引发查询超时。2024年后期,一些团队开始使用基于时间范围的乐观锁策略,减少锁冲突。建议在关键路径上使用SET LOCAL isolation_level=READ COMMITTED,并在非关键路径上使用READ UNCOMMITTED,以优化吞吐量。

十四 在配置主从复制时,必须注意从节点的wal_receiver_timeout参数。如果这个参数设置过短,比如10秒,而主节点响应慢,会导致从节点频繁断连。我曾在一个项目中,将这个参数设为60秒,解决了从节点频繁断连的问题。建议根据主节点的负载情况动态调整该参数,比如当主节点CPU使用率超过80%时,将wal_receiver_timeout设为90秒。此外,从节点的max_wal_senders_count必须大于复制进程数量,否则会限制主节点发送WAL日志的能力,影响同步效率。

十五 数据库的锁机制在集群中尤为敏感,尤其是在使用行锁时,容易引发死锁。我见过一个案例,在使用UPDATE操作时,因为未正确使用FOR UPDATE,导致多个事务同时锁定相同行,最终无法提交。建议在执行关键操作前,使用SET LOCAL lock_timeout=10000来设置事务等待时间,并在必要时使用LOCK TABLE来控制锁粒度。此外,使用pg_locks视图可以实时监控锁状态,帮助排查死锁问题。在2025年,很多团队开始结合pg_stat_activity和pg_locks进行锁冲突分析,提高了问题定位效率。