托管 PostgreSQL 市场上,各家厂商的架构选择差异极大——有的走共享存储路线,有的在存储层做深度定制。Christophe Pettus 的分析指出,Google Cloud SQL for PostgreSQL 的做法颇为不同:它回归第一原理,本质上就是一台 VM 上跑一个常规 PostgreSQL 实例,挂一块区域磁盘(regional disk),再在 Enterprise Plus 级别上加了一层独特的数据缓存。这种"朴素"架构背后有什么值得关注的细节?实际使用时又该如何配置?
架构拆解:VM + 区域磁盘 + 数据缓存
Cloud SQL 的核心思路是:不重新发明 PostgreSQL,而是让它在云上跑得更稳。
一个 Cloud SQL PostgreSQL 实例本质上是一个 Compute Engine VM,上面运行的是标准 PostgreSQL(你可以选择版本)。存储方面:
- 区域磁盘(regional disk):数据同时写入同一区域的两个可用区。如果一个可用区故障,磁盘可以在另一个可用区挂载,实例自动重启。这比单可用区磁盘的可用性高一个台阶,且对 PostgreSQL 本身完全透明——不需要你配置任何复制逻辑。
- Enterprise Plus 数据缓存:这是 Google 在存储路径上加的一层缓存。Pettus 特别提到这是 Cloud SQL 区别于其他托管方案的标志性设计。缓存位于磁盘和 PostgreSQL 之间,能显著降低读延迟,尤其对频繁访问的热数据效果明显。你不需要在 PostgreSQL 层面做任何调优来"配合"这个缓存——它是存储子系统的一部分。
这种架构的好处是:PostgreSQL 的行为和你本地跑的实例几乎一致。扩展模块、参数调优、查询计划——你积累的经验大部分可以直接迁移。
和其他托管方案的对比视角
Pettus 的"回归第一原理"评价,暗含了对其他方案的对照:
- Amazon RDS for PostgreSQL:同样是 VM 上的常规实例,但存储层用的是 EBS,没有额外的数据缓存层。RDS 的多可用区方案是通过同步复制实现的,而不是区域磁盘。
- Azure Database for PostgreSQL:Flexible Server 也是 VM 架构,但存储层的设计不同,且高可用方案的选择更受限。
- 一些新兴托管方案(如 Crunchy Bridge、Tembo):有的走共享存储 + 计算分离路线,架构更"现代",但也引入了更多与原生 PostgreSQL 行为不一致的角落。
Cloud SQL 的区域磁盘方案在故障恢复上比同步复制更简单——不需要 PostgreSQL 自己维持 WAL 流复制,故障切换时间也更可控。但代价是:区域磁盘的写入延迟比单可用区磁盘略高(因为每次写都要跨可用区确认),不过 Enterprise Plus 的缓存主要补偿的是读路径。
实操:创建和调优 Cloud SQL PostgreSQL 实例
下面是一组可以直接使用或改造的命令和配置示例。
创建一个带区域磁盘的实例
gcloud sql instances create my-pg-instance \
--database-version=POSTGRES_16 \
--tier=db-custom-4-16384 \
--region=us-central1 \
--availability-type=REGIONAL \
--storage-type=SSD \
--storage-size=100GB \
--storage-auto-increase \
--enable-point-in-time-recovery \
--backup-start-time=03:00 \
--maintenance-window-day=SUN \
--maintenance-window-hour=04 \
--edition=ENTERPRISE_PLUS
几个关键参数说明:
--availability-type=REGIONAL:启用区域磁盘,数据跨两个可用区写入。这是高可用的基础。--edition=ENTERPRISE_PLUS:启用数据缓存层。如果你选 ENTERPRISE 或更低级别,就没有这层缓存。--storage-auto-increase:存储空间自动扩容,避免磁盘满导致实例锁定(这是 PostgreSQL 的经典坑)。--enable-point-in-time-recovery:开启 PITR,依赖自动生成的 WAL 归档。
连接实例并验证缓存效果
# 获取实例连接名称
gcloud sql instances describe my-pg-instance \
--format="value(connectionName)"
# 使用 Cloud SQL Auth Proxy 连接(推荐方式)
./cloud-sql-proxy my-project:us-central1:my-pg-instance &
# 连接后检查关键参数
psql -h 127.0.0.1 -U postgres -c "
SHOW shared_buffers;
SHOW effective_cache_size;
SELECT pg_size_pretty(pg_database_size(current_database()));
"
Enterprise Plus 的数据缓存不在 PostgreSQL 的 shared_buffers 或 effective_cache_size 里体现——它位于更底层。你可以通过对比同规格 ENTERPRISE 和 ENTERPRISE_PLUS 实例的读查询延迟来感受差异:
-- 在一个有足够热数据的表上跑多次,观察平均执行时间
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*) FROM orders WHERE status = 'shipped';
在 Enterprise Plus 实例上,重复执行后 Buffers 里的 shared hit 比例不一定更高(因为缓存不在 PostgreSQL 层),但实际执行时间往往会更低——底层缓存已经在磁盘返回数据之前拦截了请求。
配置 PostgreSQL 参数的注意事项
Cloud SQL 允许你修改大部分 PostgreSQL 参数,但有几个限制:
# 修改参数(Cloud SQL 的方式是通过 gcloud,不是直接改 postgresql.conf)
gcloud sql instances patch my-pg-instance \
--database-flags=max_connections=200,work_mem=64MB
# 查看当前所有自定义参数
gcloud sql instances describe my-pg-instance \
--format="value(settings.databaseFlags)"
重要提醒:shared_buffers 在 Cloud SQL 上不能随意调大。Google 根据实例规格预设了合理值(通常是内存的 25% 左右)。强行改大可能反而降低性能,因为 Enterprise Plus 的缓存已经在存储层做了类似工作,双层缓存过大反而浪费内存。
选择建议与边界
Cloud SQL for PostgreSQL 的"回归基本原理"架构,适合以下场景:
- 需要高可用但不想自己管理流复制:区域磁盘方案比手动搭建 PostgreSQL 复制更省心,故障切换也更干净。
- 读密集型工作负载:Enterprise Plus 的数据缓存对热数据读性能有实质帮助,尤其是随机读。
- 团队已有 PostgreSQL 经验:因为架构接近原生,迁移和运维知识可以直接复用。
但也有边界需要正视:
- 写延迟敏感的场景:区域磁盘的跨可用区写入比单可用区磁盘多几毫秒。如果你的工作负载是极高频率的小事务写入(比如每秒数万条 INSERT),这个额外延迟可能累积成可感知的瓶颈。
- 需要计算存储分离:Cloud SQL 的计算和存储是绑定的。实例规格升级时存储也在同一台 VM 上,不像一些新方案可以独立扩缩。如果你需要计算节点弹性伸缩,这个架构不够灵活。
- 跨区域高可用:区域磁盘只保护同一区域内的可用区故障。跨区域的灾难恢复需要你额外配置只读副本或外部备份。
最后给一个快速检查清单,决定是否选用 Cloud SQL for PostgreSQL 时可以逐项确认:
- ✅ 工作负载读多写少,或写延迟容忍度在 5-10ms?
- ✅ 不需要计算存储分离的弹性架构?
- ✅ 高可用需求在区域级别(而非跨区域)?
- ✅ 团队熟悉标准 PostgreSQL,不想学托管方案的特殊行为?
- ✅ 预算允许 Enterprise Plus 级别(缓存只在此级别可用)?
如果以上大部分是"是",Cloud SQL 的朴素架构反而是一种优势——少一点魔法,多一点可控。