大多数托管 PostgreSQL 服务商把 standby 复制做成"尽力而为"——写主库成功就返回客户端,standby 在后台异步追赶。Azure Database for PostgreSQL Flexible Server 走了一条不同的路:standby 直接参与提交路径,每一次写操作都要等同步复制到第二台服务器确认后才向客户端返回成功。 这个架构选择对延迟、数据安全和运维方式都有实质影响,值得仔细拆解。
同步提交路径的工作机制
Azure Flexible Server 的同步复制本质上是在 PostgreSQL 层面启用了 synchronous_standby_names,将 standby 节点列为同步 standby。事务提交时,WAL 记录必须被 standby 确认接收(甚至刷盘),主库才会向客户端返回 COMMIT。
这意味着:
- 写延迟 = 主库写 WAL + 网络传输到 standby + standby 确认。跨可用区部署时,网络往返会直接叠加到每次提交上。
- 读延迟不受影响。查询走主库本地,不涉及 standby。
- standby 故障 = 写操作阻塞。如果同步 standby 不可达,主库会挂起所有写事务,直到 standby 恢复或你降级为异步复制。
对比 AWS RDS PostgreSQL 和 Google Cloud SQL for PostgreSQL,默认都是异步复制,standby 不在提交路径里。你可以选择开启同步复制,但那是可选配置,不是默认架构。
延迟影响到底有多大
理论分析不如实测。用 pgbench 在同一区域单可用区和跨可用区两种部署下跑 TPS 和延迟对比,差异一目了然。
# 初始化 pgbench 数据(在主库上执行)
pgbench -i -s 10 "host=<your-flexible-server>.postgres.database.azure.com \
port=5432 dbname=benchdb user=pgadmin sslmode=require"
# 单可用区部署:跑 60 秒只写测试
pgbench -c 32 -j 4 -T 60 -b tpcb-like \
"host=<single-az-server>.postgres.database.azure.com \
port=5432 dbname=benchdb user=pgadmin sslmode=require"
# 跨可用区部署:同样参数
pgbench -c 32 -j 4 -T 60 -b tpcb-like \
"host=<cross-az-server>.postgres.database.azure.com \
port=5432 dbname=benchdb user=pgadmin sslmode=require"
运行后关注两个指标:TPS(每秒事务数) 和 latency average(平均提交延迟)。跨可用区部署下,TPS 通常会下降 30-50%,平均延迟从几毫秒跳到十几毫秒甚至更高,具体取决于可用区之间的网络距离。
你也可以直接在数据库里查当前复制状态和延迟:
-- 查看同步 standby 配置
SHOW synchronous_standby_names;
-- 查看复制状态和 WAL 延迟
SELECT client_addr, state, sync_state,
sent_lsn, write_lsn, flush_lsn, replay_lsn,
sent_lsn - replay_lsn AS replication_lag_bytes
FROM pg_stat_replication;
sync_state 列会显示 sync,确认 standby 确实在同步模式下工作。replication_lag_bytes 在正常情况下应该接近 0——因为每次提交都等 standby 确认,理论上不会有大量积压。
当 standby 不可达时会发生什么
这是同步复制最需要警惕的场景。standby 宕机或网络中断时,主库的写操作会被阻塞,直到以下任一条件满足:
- standby 恢复连接。
- 你手动将
synchronous_standby_names改为空或切换到异步模式。 synchronous_commit被降级为local或remote_write。
Azure Flexible Server 提供了服务器参数(Server Parameters)配置界面,你可以通过 Azure CLI 或门户调整:
# 通过 Azure CLI 降级为异步复制(紧急场景)
az postgres flexible-server parameter set \
--resource-group myRG \
--server-name mypgserver \
--name synchronous_standby_names \
--value ""
# 或者降低同步级别:只等 standby 写入 WAL 缓存(不等刷盘)
az postgres flexible-server parameter set \
--resource-group myRG \
--server-name mypgserver \
--name synchronous_commit \
--value "remote_write"
降级后写操作立即恢复,但代价是数据安全窗口变大——主库崩溃时,standby 上还没刷盘的 WAL 可能丢失。这是一个明确的取舍:可用性优先还是一致性优先。
建议在运维手册中预设这个降级流程,并设定触发条件(比如 standby 连续不可达超过 N 分钟自动降级),避免手忙脚乱。
与其他托管方案的定位差异
| 维度 | Azure Flexible Server | AWS RDS PostgreSQL | GCP Cloud SQL |
|---|---|---|---|
| 默认复制模式 | 同步(standby 在提交路径) | 异步 | 异步 |
| 同步复制选项 | 默认即同步 | 可选开启 Multi-AZ 同步 | 可选开启 |
| standby 故障影响 | 写阻塞 | 写不受影响 | 写不受影响 |
| 跨 AZ 写延迟 | 较高(同步等确认) | 较低(异步) | 较低(异步) |
| RPO(数据丢失窗口) | 接近 0 | 可能丢失少量 WAL | 可能丢失少量 WAL |
Azure 的选择本质上是用延迟换 RPO。如果你的业务场景对数据丢失零容忍(金融交易、订单状态),这个默认行为反而是优势。如果更看重写入吞吐和可用性,就需要主动调参或重新评估选型。
实践建议与检查清单
- 部署前测延迟。在目标区域用
pgbench实测单 AZ 和跨 AZ 的 TPS 与延迟,不要只看规格表。 - 预设降级流程。把
synchronous_standby_names清空和synchronous_commit降级的命令写进运维手册,设定自动或半自动触发条件。 - 监控复制健康。在监控面板中持续跟踪
pg_stat_replication的sync_state和 lag,lag 突然增大可能预示 standby 压力或网络抖动。 - 读写分离要谨慎。Azure Flexible Server 的 standby 是同步的,理论上数据延迟极小,适合做读副本。但 standby 承载读查询时会和同步确认竞争 I/O,高读负载下可能反过来拖慢写提交。先压测再上线。
- 评估是否真的需要同步默认。如果你的业务能容忍秒级 RPO,异步复制 + 定期 WAL 备份可能更经济。Azure 的同步默认不是强制不可改的,但你需要主动改。
Azure 把同步复制做成默认,是一个有态度的架构决策。理解它的工作机制和边界,才能在延迟、安全、可用性之间做出清醒的选择,而不是在 standby 故障时才发现写操作全部卡住。