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

高可用方案PG分区?数据库天花板

你绝对不能用分区表来搞高可用,除非你在逻辑上把数据存放和业务逻辑彻底解耦,否则分分钟踩坑。我见过太多人把PG分区当成高可用的神药,结果因为分区键设计不当,导致主备切换时数据不一致。真实场景里,分区表在主从架构下会因为锁机制和复制延迟,造成分区级别的不一致,严重影响业务。如果你真的想用分区来提升高可用,得先搞懂复制槽、streaming复制

高可用方案PG分区?数据库天花板
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
你绝对不能用分区表来搞高可用,除非你在逻辑上把数据存放和业务逻辑彻底解耦,否则分分钟踩坑。我见过太多人把PG分区当成高可用的神药,结果因为分区键设计不当,导致主备切换时数据不一致。真实场景里,分区表在主从架构下会因为锁机制和复制延迟,造成分区级别的不一致,严重影响业务。如果你真的想用分区来提升高可用,得先搞懂复制槽、streaming复制、逻辑复制这些底层机制。别想着用分区来做数据分片,那是分布式系统的活,不是单实例PG能扛的。关键点在于怎么绕过分区带来的复制瓶颈,比如用逻辑复制订阅和发布,或者把分区策略和业务负载结合起来。别盲目追求分区,得看你的业务场景是否适用,否则就是给自己挖坑。

▌ 技术参考


PG分区不是高可用的解药,它在单节点架构下反而会成为高可用的绊脚石。你要是搞错了分区策略,主从切换后可能会有数据丢失或者分区级别的不一致。比如,如果你用范围分区,主节点负责写入,从节点只读,复制过程如果卡在某个分区,那就完了。我见过一个项目,他们用范围分区,结果主节点死机,从节点因为复制延迟,导致分区数据不一致,整个故障恢复过程花了将近6小时。关键点在于,分区表会引入锁机制,影响复制的同步效率。如果你非要用分区来做高可用,记得提前设置好复制槽,确保主节点不会因为复制压力导致性能下降。


要实现高可用,PG分区必须和主从复制配合使用,但不能单纯依赖分区表本身。逻辑复制是更好的选择,因为它可以跨节点同步数据,而不会受分区键的限制。比如,你可以在主库上创建逻辑复制槽,然后在从库上配置订阅,订阅的表可以是整个数据库或者部分表。分区表如果被逻辑复制订阅,必须在主库和从库上都存在,而且分区策略要一致。一旦主库的某个分区数据更新,从库必须同步到对应分区,否则就会导致数据不一致。如果你用的是PostgreSQL 15及以上版本,可以试试用逻辑复制结合分区表,这样能实现更灵活的高可用方案。


分区表的高可用方案最常见的是搭配流复制和逻辑复制,但流复制在处理分区表时会因为锁和复制延迟,导致从库无法及时同步。我见过一个案例,他们用范围分区,主库频繁更新某个分区的数据,结果从库因为复制槽满了,导致主库无法继续写入。这时候就得用pg_wal_replay_pause来暂停复制,但这样又会影响高可用。所以,分区表在高可用场景下要格外小心,尤其是分区键和主从切换的节奏不匹配时。建议在使用分区表之前,测试一下复制延迟和锁冲突的情况,避免大规模故障。


PG分区的高可用性取决于分区键的选择和复制策略的配置。如果你的分区键是时间,比如按天分区,那你必须确保主从切换时,时间分区的数据能正确同步。否则,比如主库切换到一个新节点,而从库还在同步旧分区的数据,就会出现数据不一致。这时候你可以用逻辑复制来同步整个表,但要注意分区表在逻辑复制中的兼容性。有些分区类型不支持逻辑复制,比如哈希分区,只能用范围或者列表分区。另外,在配置逻辑复制的时候,一定要注意复制槽的大小和生命周期,避免主库因为复制槽满了而拒绝连接。


很多公司把PG分区当作高可用的解决方案,结果发现分区表的主从复制不是那么好搞。比如,主库在写入数据的时候,如果没有正确配置wal_level为logical,那么逻辑复制就无法正常工作。我之前在做高可用方案的时候,硬是卡在wal_level配置上,花了两天时间排查。所以,如果你用逻辑复制来同步分区表,必须在主库上设置wal_level为logical,并且配置好replication slot。同时,从库要使用逻辑解码,确保能正确解析主库的变更。记住,逻辑复制不是万能的,它有性能开销,尤其是分区表数据量大的时候,复制的延迟会更明显。


在实际操作中,如果你想要用分区表来提升高可用,必须考虑复制延迟和锁冲突的问题。比如,主库在处理写操作时,可能会因为锁机制导致某些分区的复制进度落后。这时候你得用pg_stat_replication来监控复制状态,或者用pg_waldump来查看复制日志。另外,有些数据库工具,比如pg_basebackup,不支持分区表的直接备份,这就需要你手动处理。比如,你可以用pg_dump结合--format=custom参数来导出整个分区表结构,再用pg_restore恢复到从库。但这种方法效率不高,尤其是分区很多的情况下,会浪费很多时间。


高可用方案中,分区表的复制策略需要精细化。比如,如果你用的是范围分区,并且主库频繁写入新分区的数据,那你必须确保从库能及时创建对应的新分区。否则,主库写入了新分区,而从库还没同步,就会出现数据不一致。这时候,可以考虑在从库上使用触发器自动创建新分区,或者用定时任务检测主库的分区情况,并同步到从库。但这种方法容易出错,尤其是在数据量大的时候,得小心Partition Pruning的问题。我记得有次因为没处理好这个,导致从库的数据查询结果和主库不一致。


PG分区的高可用性还取决于你的业务场景。比如,如果你的业务是读多写少,那分区表可能反而能帮助你减少查询压力。但如果你的业务是写密集型,那分区表就容易成为瓶颈。我见过一个电商系统,他们用的时间分区表在写入高峰期会导致从库复制滞后,因为他们没有合理设置复制槽的保留时间,结果主库的wal日志堆积,从库无法及时同步。所以,高可用方案不能只看分区,得看业务负载和复制策略的配合。在高并发的写入场景下,分区表的复制延迟会更严重,这时候需要考虑使用分布式数据库,而不是单实例PG。


如果实在要用PG分区来做高可用,那我建议你用逻辑复制结合流复制的方式,把分区表的数据分发到多个从库中。但注意,逻辑复制的性能开销很大,尤其是分区表数据量大的时候,每次复制都要解码和应用变更,会占用大量CPU和内存资源。你可以用pgbench来测试一下复制的性能,看看在不同分区数量下的延迟情况。另外,有些分区类型的复制容易出问题,比如按时间分区,主库切换后,从库可能无法正确处理时间分区的数据,导致查询错误或者数据丢失。这时候,就得在从库上做额外的配置,比如调整max_replication_slots和max_wal_senders的参数。


分区表的高可用方案需要你对主从复制的机制非常熟悉。比如,主库的WAL日志在复制过程中可能会因为分区键的冲突而无法正确传输,这时候你可以用pg_wal_replay_pause来暂停复制,但这样又会影响高可用。或者,你可以用pg_rewind工具来修复主从不一致的问题,不过这个工具对分区表的支持不是很好,容易出错。我之前用pg_rewind修复过一次分区表的不一致,结果发现某些分区的数据无法正确同步,导致整个系统需要重启。所以,分区表的高可用配置要特别谨慎,不能轻易依赖这些工具。

十一
在高可用方案中,分区表的配置还需要考虑复制槽的生命周期。比如,如果你的复制槽保留时间太短,主库可能会在复制过程中丢掉WAL日志,导致从库无法同步。这时候你得用pg_resetwal来重置WAL日志,但这对数据库的稳定性影响很大,必须在维护窗口进行。另外,复制槽的大小如果设置得不合理,也会导致主库资源浪费。我之前在做高可用测试的时候,发现复制槽默认的保留时间太短,导致主库频繁重启复制槽,反而影响了整体的复制效率。所以,复制槽的配置要根据业务的复制延迟和日志增长速度来调整。

十二
PG分区的高可用方案还可以结合外部工具,比如主从切换工具、监控工具和数据同步工具。比如,你可以在主库和从库之间使用Patroni来管理主从切换,同时用Prometheus和Grafana来监控复制状态。但要注意,Patroni在处理分区表的时候,有时候会因为锁冲突而无法正确切换主从。这时候你可以用pg_rewind来修复,或者直接重启主库,但这对业务影响很大。所以,我建议你把分区表的高可用方案拆分成多个步骤,比如先做逻辑复制,再做主从切换,最后做数据校验。

十三
高可用性要求主从切换后数据完全一致,所以在使用分区表的时候,必须确保每个分区都能独立同步。也就是说,主库和从库在分区层面不能有差异,否则切换后就会出问题。比如,主库可能有一个分区P1,而从库可能没有,这时候切换主从就会导致数据丢失。这时候你可以用pg_dump或pg_basebackup来备份整个分区表结构,再恢复到从库。不过这种方法效率低,而且容易出错,尤其是在数据量大的时候。我之前用pg_dump导出分区表的时候,发现某些分区的数据没有正确导出,导致从库的数据结构和主库不一致。

十四
如果你的业务场景允许,可以考虑用物理复制结合分区表的方式。比如,主库通过流复制把整个数据库复制到从库,然后从库处理查询请求。这时候,分区表不会造成复制延迟,因为物理复制是直接复制数据文件,不需要解码变更。不过,物理复制在分区表的高可用方案中也有它的局限,比如无法处理动态分区,主库切换后,从库可能需要手动调整分区结构。我之前在做物理复制测试的时候,发现从库的分区结构和主库不一致,导致查询时出现错误。这时候,就得在切换主从之前,确保所有分区在从库上都存在。

十五
最后,别忘了在高可用方案中加入监控和自动修复机制。比如,你可以用pg_stat_replication来监控主从复制的状态,用pg_locks来查看锁冲突的情况,用pg_wal_lsn_status来检查WAL日志的同步进度。这些监控指标能帮助你发现潜在的问题。另外,如果你发现某个分区的数据不一致,可以考虑用pg_rewind来修复,但这对分区表支持有限,最好还是用逻辑复制或者物理复制来处理。总之,分区表的高可用方案不是灵丹妙药,得结合你的实际业务和系统负载来设计,不然分分钟翻车。