在单台服务器上自托管多个数据库实例
自托管数据库的承诺
云托管数据库固然方便——直到账单寄来的那一刻。对于运行多个项目的团队来说,每个项目都需要独立的 Postgres 实例,一旦超过三四个数据库,成本计算就会发生根本性转变。
但现实是,将多个数据库实例塞进同一台机器并非只是多运行几个容器那么简单。内存竞争、磁盘 I/O 冲突以及备份编排都会成为突出的问题,而这些都是托管服务悲悲替你处理的。
我们的方案:在单台服务器上运行多个 Supabase 栈
我们在一台专用服务器上运行多个完整的 Supabase 栈——每个栈包含 Postgres、GoTrue、PostgREST、Realtime 和 Storage——完全通过 Docker Compose 进行编排。
每个栈拥有独立的 compose 文件、独立的网络命名空间以及独立的数据卷。核心架构决策:不共享 Postgres 集群。每个项目拥有完全隔离的数据库实例。运行多个 Postgres 进程的开销是真实存在的——每个空闲实例大约占用 200-400 MB 内存——但完全隔离带来的运维简洁性超过了资源成本。
真正重要的资源限制
services:
db:
image: supabase/postgres:15.6
deploy:
resources:
limits:
memory: 2G
cpus: '2.0'
reservations:
memory: 512M
cpus: '0.5'Docker 资源限制是第一道防线。没有它们,一个失控的查询可能会耗尽机器上所有其他数据库的资源。预留配置确保每个实例即使在竞争激烈时也始终拥有最低限度的资源分配。
跨实例的备份编排
多数据库的问题不在于如何备份——pg_dump 可以可靠地处理这一点。问题在于如何编排备份,使它们不会同时运行并导致磁盘 I/O 饱和。
我们通过简单的带偏移量的 cron 计划来错开备份。实例 A 在 02:00 备份,实例 B 在 02:15,实例 C 在 02:30。每次备份通过 gzip 管道传输并上传至对象存储。所有实例的总备份窗口:不到 45 分钟。
无监控栈的监控
一个常见陷阱:为了监控服务器而部署 Prometheus、Grafana 和 AlertManager——从而消耗掉你试图保护的资源。在我们的规模下,轻量级方案效果更好。
一个 shell 脚本每五分钟通过 cron 运行一次,用 pg_isready 检查每个 Postgres 实例,测量每个卷的磁盘使用量,并在任何阈値被突破时向通知端点发送摘要。总资源成本:可以忽略不计。
何时停止自托管
当团队了解 Postgres 运维、工作负载可预测、且成本节省足以证明运维开销合理时,自托管多个数据库才有意义。一旦上述任何条件发生变化——快速扩展需求、托管服务的合规要求,或团队人员流动——天平便会重新倾向托管服务。
最好的基础设施决策是可逆的。Docker 卷可以导出,pg_dump 文件可以在任何地方恢复,应用层不应该关心数据库在哪里。这种可移植性才是容器化方案真正的价値所在——而不仅仅是节省成本。