自托管数据库评估与云数据库 PostgreSQL 对比
文档版本:v1.0 评估日期:2026-09-23 评估范围:PropOS 生产环境数据库(PostgreSQL 15.17)当前自托管部署形态 数据来源:生产服务器实测 + 部署脚本(
backend/deploy.sh、scripts/setup_server.sh)+ 备份服务源码(database_backup_service.dart) 结论摘要:当前方案负载容量充足,但存在「备份与数据库同盘同源」的灾难恢复死角;云数据库迁移成本可控(数据仅 48MB),按预算分三档推进建议见第七章。
一、背景与评估目的
PropOS 生产环境采用单台腾讯云服务器 + Docker 容器编排的部署形态,PostgreSQL 数据库以 Docker 容器方式与后端、Nginx、Redis 同机运行。
本评估针对以下问题给出结论:
- 当前自托管数据库部署方式有哪些弊端与风险?
- 是否值得独立购买云数据库 PostgreSQL(TencentDB for PostgreSQL)?
- 如迁移,成本与路径是什么?如暂不迁移,如何以最低成本消除关键风险?
二、当前部署实测现状
2.1 部署拓扑
单台腾讯云服务器(约 2C / 1.7GB 内存 / 单盘 40GB,无 Swap)
│
├── propos-nginx (80/443,nginx:alpine)
├── propos-backend (8080,Dart AOT,内存占用 ~92MB)
├── propos-redis (6379,redis:7-alpine)
└── propos-postgres (5432,postgres:15.17-alpine,内存占用 ~97MB)
│
└── Docker Volume: propos-pgdata(数据)
propos-uploads(上传文件 + 数据库每日备份 pg_dump)⚠️ 同盘
后端通过 Docker 内网 propos-net 以 DNS propos-postgres:5432 访问数据库;5432 端口不对外暴露。
2.2 实测数据(2026-09-23)
| 项目 | 实测值 | 备注 |
|---|---|---|
| 服务器内存 | 总量 1.7GiB,已用 624MiB,可用 634MiB | Swap = 0 |
| 服务器磁盘 | /dev/vda1 单盘 40GB,已用 25GB(66%),剩余 13GB |
Docker 目录占 18GB |
| PostgreSQL 版本 | 15.17(alpine,musl 编译) | 容器已运行 6 周 |
| 数据库大小 | 48MB | 体量极小 |
| 活动连接数 | 14 | 负载很低 |
shared_buffers |
128MB | 默认值,未调优 |
| 容器内存占用 | postgres 97MiB / backend 92MiB / redis 10MiB / nginx 6MiB | 现有负载下资源充裕 |
| 自动备份 | 每日 02:00(北京时间)pg_dump 成功,已连续 20+ 天 | 文件约 5MB/天,保留 20+ 天 |
| 备份存储位置 | /var/lib/docker/volumes/propos-uploads/_data/backups/ |
与数据库同一块磁盘、同一台机器 |
| 异地备份 | 无 | DatabaseBackupService 无 COS/OSS 上传逻辑 |
2.3 与规划文档的差距
| 项目 | 规划文档(TENCENT_CLOUD_SERVER_SPEC.md 等) | 实际 |
|---|---|---|
| 服务器规格 | 4C16G(最低 8G + Swap) | ~2C1.7G,无 Swap |
| 数据盘 | 独立 CBS 200GB + 每日快照保留 7 天 | 单盘 40GB,无独立数据盘/快照证据 |
| 数据库备份 | pg_dump 导出后上传 COS,保留 30 天 | 仅存本机同盘(UAT 验收书要求项未落实) |
实测差距说明:当前为低成本运行形态。评估的核心矛盾不在性能(负载远低于容量),而在灾备与运维风险。
三、核心弊端分析
按严重程度分级:
🔴 P0 — 备份与数据库「同源死角」(最致命)
数据库数据、上传文件、全部备份文件落在同一台服务器、同一块磁盘上。
- 磁盘损坏 / 系统盘故障 / 服务器被误删 / 被入侵 → 数据与备份同时丢失,无任何恢复来源;
- 规划文档中的「上传 COS + CBS 快照」均未实际落地;
- 这是当前唯一的「一票否决级」风险:其余风险最多导致停服,此项直接导致数据永久丢失。
🔴 P0 — RPO = 24 小时,且恢复能力未经演练
- 每日仅一次全量备份,最坏情况丢失近 24 小时的合同、账单、核销记录——对财务属性数据不可接受(PRD 目标 RPO ≤ 24h / RTO ≤ 4h 属于及格线而非优秀);
- 备份「文件存在」≠「备份可恢复」,尚无一次恢复演练记录;
- RTO 全靠人工:服务器尚可登录时约 30–60 分钟;机器完全损毁需新购机器 + 重建环境 + 恢复 dump,数小时起步。
🟠 P1 — 无 Swap + 内存吃紧,存在 OOM 波及数据库的风险
- 1.7GB 总内存承载 4 个容器,可用仅 634MB 且无 Swap 兜底;
- 后端一旦出现内存尖峰(大报表导出、文件批处理、并发高峰),OOM Killer 可能直接终止 PostgreSQL 进程;
- 虽有
--restart unless-stopped会自动重启,但会造成连接中断、崩溃恢复耗时,极端情况下引发数据一致性问题。
🟠 P1 — 磁盘 66% 已用,逼近「数据库停摆」硬天花板
- 剩余 13GB;Docker 目录占 18GB(历次部署镜像积累);
- 增长源:镜像版本、上传文件(CAD SVG / 合同 PDF / 工单照片)、WAL、备份文件本身;
- 磁盘写满 = PostgreSQL 无法写 WAL = 数据库直接拒绝写入——这比内存问题更硬、更早触发。
🟡 P2 — 零托管能力:补丁、调优、监控全部自担
- 安全补丁(15.17 → 后续小版本 CVE 修复)需手动重建容器升级;
- 关键参数维持默认(
shared_buffers128MB),无pg_stat_statements慢查询分析、无性能洞察视图; - WAL 膨胀、长事务、连接泄漏、autovacuum 异常等故障全部自行排查。
🟡 P2 — 安全面薄弱
- 无静态数据加密(磁盘未加密时数据文件裸存)、无数据库审计日志能力(合规场景缺失);
- 备份文件未加密、未异地——服务器被入侵时,攻击者可一并窃取/勒索备份。
🟡 P2 — 无高可用与扩展能力
- 单实例运行,宿主机故障 = 数据库不可用,无主备、无自动故障转移;
- 无法增加只读副本、无法读写分离;扩容只能升级整机(存在停机风险)。
四、云数据库 PostgreSQL 方案对比(腾讯云 TencentDB for PostgreSQL)
| 维度 | 当前(Docker 自托管) | TencentDB for PostgreSQL |
|---|---|---|
| 可用性 | 单实例,宿主机故障即停服 | 高可用版主备双节点自动切换,SLA ≥ 99.95% |
| 备份 / RPO | 日备 1 次、存同盘,RPO 最坏 24h | 自动全量 + 增量备份,异地多副本存储,支持 PITR 按时间点回档(秒级) |
| 恢复 / RTO | 人工操作,小时级 | 控制台一键回档 / 克隆实例,分钟级 |
| 存储可靠性 | 单块云盘 | 三副本分布式存储,可靠性 99.9999999% |
| 运维负担 | 补丁、调优、扩容、排障、监控全自管 | 自动补丁、自动监控告警、慢查询 / 锁等待 / 连接数视图 |
| 安全能力 | 无静态加密、无审计日志 | 存储加密(TDE)、SSL、VPC 内网隔离、IP 白名单、可选审计 |
| 扩展性 | 升级整机 / 迁移磁盘 | 一键升配(秒级闪断)、在线扩容存储、新增只读副本 |
| 网络延迟 | 容器内网 < 1ms | 同 VPC 内网 1–2ms(当前负载完全够用) |
| 外部依赖 | 无 | 依赖 VPC 网络与云服务可用性 |
| 成本结构 | 已含在服务器费用内(隐性成本 = 运维时间 + 灾备风险) | 额外月费(见第五章) |
备选形态说明
| 形态 | 特点 | 适用性 |
|---|---|---|
| PG 基础版(单节点) | 价格约为高可用版 50%,含自动备份 / PITR,无主备 | 预算敏感仍想获得托管灾备能力 |
| PG 高可用版(主备) | 主备自动切换 + 全托管 | 推荐档:财务数据 + 无 DBA 团队 |
| TDSQL-C PG Serverless | 按 CCU 弹性计费,低负载成本极低 | 注意其 PG 内核版本相对较老,迁移前需验证兼容性 |
五、费用测算(估算,以腾讯云购买页实时价格为准)
| 选项 | 估月费 | 说明 |
|---|---|---|
| 现状整机(2C2G 轻量服务器) | ≈ ¥60–100/月 | 数据库共享在服务器资源内 |
| PG 基础版 2C4G + 50G SSD | ≈ ¥250–350/月 | 自动备份 / PITR,无主备 |
| PG 高可用版 2C4G + 50G SSD | ≈ ¥400–600/月(包年可享 6 折上下) | 主备 + PITR + 全托管,推荐评估档 |
| TDSQL-C PG Serverless | 低负载 ≈ ¥50–150/月 | 弹性计费;内核版本需验证 |
规格费参考:腾讯云文档示例(16C32G 包月 ¥4096)折算约 ¥128/GB 内存/月,小规格单价以官方价格计算器为准。存储约 ¥0.72/GB/月,备份空间为实例容量 200% 内免费。
成本视角结论:
- 云数据库对当前极低负载(48MB、14 连接)而言,买的是「不丢数据的确定性」与「免除运维」,不是性能;
- 若预算敏感:先执行第六章「零成本止血」,可将最致命风险压到接近零成本;
- 若重视长期省心:直接迁移高可用版,每月增量成本约等于半天运维工时,即可获得 PITR + 主备 + 托管监控。
六、迁移成本与路径
6.1 迁移成本(极低)
| 项目 | 评估 |
|---|---|
| 数据量 | 48MB,pg_dump → pg_restore 分钟级完成 |
| 停机窗口 | 可控制在 30 分钟内(低峰期) |
| 代码改动 | 仅 DATABASE_URL 指向变更(云库 VPC 内网地址);无需修改业务代码 |
| 部署改动 | docker run 后端容器时移除对 propos-postgres 的同网络依赖 |
| 应用内备份系统 | 保留作手动导出入口;自动备份职责移交云端 |
6.2 迁移步骤概要
- 购买云库(同 VPC/可用区,PG 15 或更高),配置白名单仅放行服务器内网;
- 低峰期:
pg_dump生产库 →pg_restore到云库; - 停机后二次增量导出/导入(或直接以 dump 差异补齐),校验行数 / 关键表;
- 修改
/opt/propos/.env的DATABASE_URL→ 云库内网地址; - 重启
propos-backend容器,验证:登录、合同列表、账单、文件上传下载; - 观察 24–48 小时(慢查询、连接数、错误日志),确认后下线
propos-postgres容器; - 保留停机前最后一次本地备份至少 30 天作为回滚兜底。
6.3 回滚预案
- 切换后若发现异常:将
DATABASE_URL指回propos-postgres:5432(容器保留未删)→ 恢复备份 → 重启后端,预计 15 分钟内恢复原状; - 云库侧在确认稳定前不释放,按量计费模式下短期成本可控。
七、风险治理建议(按预算分三档)
| 档位 | 动作 | 追加成本 | 效果 |
|---|---|---|---|
| A. 零成本止血(建议立即执行) | ① 每日 pg_dump 同步至腾讯云 COS(异地);② 执行一次恢复演练并记录;③ 服务器增加 2GB Swapfile;④ 清理旧 Docker 镜像(docker image prune);⑤ 配置磁盘 / 内存 / 备份成功性告警 |
≈ ¥0(COS 每月几分钱) | 消除「数据 + 备份一起丢」的 P0 死角;释放约 5–10GB 磁盘;降低 OOM 风险 |
| B. 低成本增强 | 在 A 基础上引入 WAL 归档(pgBackRest / WAL-G)推送 COS,RPO 从 24h 降至分钟级 | ≈ ¥0–50/月 | 获得接近 PITR 的恢复能力,同时保持自托管 |
| C. 托管迁移(推荐评估) | 迁移至 PG 高可用版 2C4G(或先按量计费试用),同 VPC 内网直连 | ≈ ¥400–600/月 | 彻底免除数据库运维;RPO ≈ 秒级、RTO ≈ 分钟级;获得主备 / 审计 / 监控能力 |
决策要点
- 数据重要性 vs 预算:PropOS 承载合同、账单、核销等财务属性数据,单次数据丢失的事故成本远超每月数百元;若团队无专职 DBA,托管价值显著。
- 最低底线:无论是否迁移云库,「档位 A」都应立即执行——当前备份与数据同盘,属于不可接受的单点风险。
- 性能非决策因素:48MB / 14 连接的负载下,自托管与云库的性能差异可忽略;决策依据是灾备与运维。
附录 A:本次评估实测命令(只读)
# 容器状态与镜像
ssh propos-server "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'"
# 磁盘与内存
ssh propos-server "df -h; free -h"
# 数据库大小 / 连接数 / 关键参数
ssh propos-server "docker exec propos-postgres psql -U propos -d propos -tAc \
\"SELECT pg_size_pretty(pg_database_size('propos'));\""
ssh propos-server "docker exec propos-postgres psql -U propos -d propos -tAc \
'SELECT count(*) FROM pg_stat_activity; SHOW shared_buffers;'"
# 备份文件与位置
ssh propos-server "ls -lh /var/lib/docker/volumes/propos-uploads/_data/backups/ | tail -20"
附录 B:相关文档索引
| 文档 | 关系 |
|---|---|
docs/guide/TENCENT_CLOUD_SERVER_SPEC.md |
服务器选型与备份策略规划(§六 快照与备份策略) |
docs/backend/同机部署与冲突规避指南.md |
当前容器拓扑与资源命名规范 |
docs/backend/guide/POSTGRES_USAGE_GUIDE.md |
PostgreSQL 运维命令与备份策略 |
backend/lib/modules/database/services/database_backup_service.dart |
应用内备份实现(pg_dump,本地存储) |
PropOS_UAT验收确认书.md |
「备份文件存储在 COS/OSS」验收项(当前未落实) |