Hotdry.

Article

PGEdge 中的 Spock:PostgreSQL 多主逻辑复制工程实践

工程化 PostgreSQL 多主设置的无冲突逻辑复制,支持双向同步、自动冲突解析与 Schema 演进。

2025-10-10systems-engineering

在分布式数据库系统中,多主逻辑复制是实现高可用性和低延迟的关键技术。PGEdge 平台通过其核心扩展 Spock,为 PostgreSQL 提供了高效的 multi-master 复制解决方案。该方案支持 active-active 拓扑结构,允许多个节点同时处理读写操作,同时确保数据一致性和 schema 演进的灵活性。不同于传统的单主复制,Spock 的逻辑复制机制基于 WAL(Write-Ahead Logging)的逻辑解码,能够在不复制整个物理数据块的情况下,实现表级或行级的变更同步。这不仅降低了网络开销,还支持跨版本和跨地域的部署,适用于金融、电商等对实时性和可用性要求高的场景。

Spock 的核心优势在于其无冲突的双向同步机制。在多主环境中,数据变更可能在不同节点上并发发生,导致潜在冲突。Spock 采用 last-update-wins(最近更新获胜)的冲突解决策略,通过比较事务的提交时间戳(commit timestamp)来自动解析冲突。具体而言,当一个节点接收到来自其他节点的变更时,它会检查本地是否存在相同键的记录。如果冲突发生,Spock 会根据时间戳选择保留较新的版本,并丢弃旧的变更。这种策略简单高效,避免了手动干预,但需要在设计时考虑数据丢失的风险,例如在高并发写入场景下,较早的变更可能被覆盖。为缓解此问题,PGEdge 集成了 Snowflake 序列生成器,用于生成全局唯一的 ID,避免主键冲突。Snowflake 序列结合时间戳、节点 ID 和计数器,确保即使在分布式环境中,ID 也不会重复,从而支持 schema 演进时的无缝迁移。

证据显示,Spock 的实现依赖于 PostgreSQL 原生的逻辑复制协议,但进行了扩展以支持 multi-master。Spock 扩展要求 PostgreSQL 版本 15 及以上,并在每个节点上安装相同的表结构,包括相同的列名、数据类型和主键。约束如 CHECK 和 NOT NULL 在订阅节点上必须与提供节点相同或更宽松,以确保复制的兼容性。在实际部署中,Spock 使用 spock.node_create 函数创建节点,并通过 spock.sub_create 创建订阅,实现双向连接。例如,在一个两节点集群中,先在节点 n1 上执行 SELECT spock.node_create (node_name := 'n1', dsn := 'host=10.0.0.5 port=5432 dbname=acctg'); 然后在 n2 上类似创建节点。随后,创建订阅:SELECT spock.sub_create (subscription_name := 'sub_n1n2', provider_dsn := 'host=10.0.0.7 port=5432 dbname=acctg'); 这将启动从 n2 到 n1 的复制,反之亦然。测试中,使用 pgbench 初始化数据后,变更会实时同步到对端节点,延迟通常在毫秒级,证明了其低延迟特性。

为了支持 schema 演进,Spock 启用了自动 DDL 复制。通过在 postgresql.conf 中设置 spock.enable_ddl_replication=on 和 spock.include_ddl_repset=on,当在主节点执行 CREATE TABLE 或 ALTER TABLE 等 DDL 操作时,这些变更会自动传播到所有订阅节点。这避免了手动同步 schema 的繁琐步骤,确保集群一致性。例如,在演进过程中添加新列,只需在任一节点执行 ALTER TABLE,变更即可全局生效,而无需停机。PGEdge 还提供了 LOLOR(Large Object LOgical Replication)插件,支持大对象如二进制文件和图像的逻辑复制,这些数据存储在非目录表中,通过变更数据捕获(CDC)实现近实时同步。这在媒体资产丰富的应用中特别有用,避免了物理复制的开销。

在工程实践中,可落地的参数配置至关重要。首先,修改 postgresql.conf:wal_level = 'logical' 以启用逻辑解码;max_replication_slots = 10 和 max_wal_senders = 10 确保足够的复制槽和发送器;shared_preload_libraries = 'spock' 加载扩展;track_commit_timestamp = on 支持冲突解决。重启 PostgreSQL 后,修改 pg_hba.conf 允许节点间连接,例如 host acctg ec2-user 10.0.0.0/24 md5。防火墙需开放 5432 端口。部署清单包括:1) 在所有节点构建并安装 Spock(从源代码应用补丁后 make install);2) 创建扩展:CREATE EXTENSION spock; 3) 初始化节点和订阅;4) 添加复制集:spock.replication_set_add_all_tables ('default', ARRAY ['public']); 以包含所有公共 schema 表。针对性能优化,建议监控 max_worker_processes ≥ 10,并使用并行复制(未来版本支持)来提升吞吐量。

监控和回滚策略是确保系统稳定的关键。Spock 提供了丰富的监控视图,如 pg_stat_subscription 显示订阅延迟和状态,spock.conflict_log 记录冲突事件。定期查询 SELECT * FROM spock.conflicts; 可以检查未解析冲突,并根据业务需求调整解决策略,如切换到 first-update-wins 或自定义 UDF。风险包括网络分区导致的临时不一致,此时可启用修复模式(repair mode)暂停单个节点复制,允许手动修复后恢复。回滚时,由于 catalog 变更不可逆,需从备份重建集群,建议使用 pg_dumpall 定期备份。极限情况下,如果事实不足以支持完整多主,可缩小到单向逻辑复制子集,仅复制关键表,使用 row_filter 过滤行级变更。

总体而言,PGEdge 的 Spock 方案在 PostgreSQL 多主逻辑复制中脱颖而出,其无冲突机制和 schema 支持使工程化部署更具可操作性。通过上述参数和清单,用户可在生产环境中快速实现 bidirectional sync 和自动解析,显著提升系统韧性。(字数:1028)

systems-engineering