chore(deploy): 数据库与各服务增加资源限制和优雅关闭保护
- postgres 增加 mem_limit/cpus/shm_size/stop_grace_period 与 PG 性能参数(shared_buffers 等,env 可覆盖);backend/web 增加 内存/CPU 限额与更长的优雅关闭宽限(生产与开发编排同步) - ubuntu-deploy.sh 增加部署前磁盘空间预检,防止备份或迁移 中途磁盘写满 - .env.server.example 补充资源变量;文档补充容器资源限制说明
This commit is contained in:
@@ -33,6 +33,19 @@ DATABASE_STATEMENT_TIMEOUT_MS=15000
|
||||
DATABASE_SLOW_QUERY_THRESHOLD_MS=500
|
||||
# PostgreSQL 原生慢查询日志阈值(毫秒);-1 关闭
|
||||
POSTGRES_LOG_MIN_DURATION_STATEMENT_MS=500
|
||||
# PostgreSQL 容器资源与性能参数(按服务器内存调整;默认值按 2G 内存机器设置,
|
||||
# 4G+ 机器可将 shared_buffers 提到 512MB、effective_cache_size 提到 2GB):
|
||||
POSTGRES_MEM_LIMIT=1g
|
||||
POSTGRES_CPUS=2
|
||||
POSTGRES_SHARED_BUFFERS=256MB
|
||||
POSTGRES_EFFECTIVE_CACHE_SIZE=1GB
|
||||
POSTGRES_WORK_MEM=8MB
|
||||
POSTGRES_MAINTENANCE_WORK_MEM=128MB
|
||||
# 后端与 Web 容器限额(内存紧张的小机器可相应收紧)
|
||||
BACKEND_MEM_LIMIT=512m
|
||||
BACKEND_CPUS=1
|
||||
WEB_MEM_LIMIT=256m
|
||||
WEB_CPUS=0.5
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=info
|
||||
|
||||
@@ -197,6 +197,32 @@ check_compose_config() {
|
||||
docker compose config >/dev/null || fail "Docker Compose 配置校验失败。"
|
||||
}
|
||||
|
||||
# 部署前磁盘空间预检:备份目录所在文件系统至少要有首份备份 + 现有备份量 2 倍的余量。
|
||||
# 不足时直接失败,避免备份或迁移过程中磁盘写满导致数据库不可用。
|
||||
ensure_disk_space() {
|
||||
local backup_root="${PROJECT_ROOT}/backups"
|
||||
local floor_kib=1048576 # 1GiB
|
||||
local existing_kib=0 require_kib free_kib
|
||||
|
||||
mkdir -p "${backup_root}" 2>/dev/null || true
|
||||
|
||||
if [[ -d "${backup_root}" ]]; then
|
||||
existing_kib="$(du -sk "${backup_root}" 2>/dev/null | awk '{print $1}' || true)"
|
||||
existing_kib="${existing_kib:-0}"
|
||||
fi
|
||||
|
||||
require_kib=$((existing_kib * 2))
|
||||
[[ ${require_kib} -lt ${floor_kib} ]] && require_kib=${floor_kib}
|
||||
|
||||
free_kib="$(df -Pk "${PROJECT_ROOT}" 2>/dev/null | awk 'NR==2 {print $4}' || true)"
|
||||
free_kib="${free_kib:-0}"
|
||||
|
||||
log "磁盘空间预检:可用 ${free_kib} KiB,备份目录已占用 ${existing_kib} KiB,要求至少 ${require_kib} KiB"
|
||||
if [[ ${free_kib} -lt ${require_kib} ]]; then
|
||||
fail "磁盘可用空间不足(可用 ${free_kib} KiB,需 ≥ ${require_kib} KiB)。请清理磁盘或调小 DB_BACKUP_KEEP 后重试。"
|
||||
fi
|
||||
}
|
||||
|
||||
pull_base_images() {
|
||||
log "拉取基础镜像"
|
||||
docker compose pull --ignore-buildable
|
||||
@@ -482,6 +508,7 @@ main() {
|
||||
validate_env_file
|
||||
confirm_reset_database
|
||||
ensure_data_dir
|
||||
ensure_disk_space
|
||||
deploy_stack
|
||||
wait_for_health
|
||||
print_applied_migrations
|
||||
|
||||
@@ -16,8 +16,20 @@ services:
|
||||
"pg_stat_statements.track=all",
|
||||
"-c",
|
||||
"log_min_duration_statement=${POSTGRES_LOG_MIN_DURATION_STATEMENT_MS:-500}",
|
||||
"-c",
|
||||
"shared_buffers=${POSTGRES_SHARED_BUFFERS:-256MB}",
|
||||
"-c",
|
||||
"effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB}",
|
||||
"-c",
|
||||
"work_mem=${POSTGRES_WORK_MEM:-8MB}",
|
||||
"-c",
|
||||
"maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-128MB}",
|
||||
]
|
||||
restart: unless-stopped
|
||||
mem_limit: ${POSTGRES_MEM_LIMIT:-1g}
|
||||
cpus: ${POSTGRES_CPUS:-2}
|
||||
shm_size: 512mb
|
||||
stop_grace_period: 60s
|
||||
logging: *json-log-rotation
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
|
||||
@@ -8,6 +8,7 @@ services:
|
||||
postgres:
|
||||
image: docker.m.daocloud.io/library/postgres:16-bookworm
|
||||
# 开启 pg_stat_statements,便于定位生产环境累计最耗时的 SQL。
|
||||
# 内存类参数按 2G 内存机器给出默认值,请按服务器内存调整(见 .env.server.example)。
|
||||
command:
|
||||
[
|
||||
"postgres",
|
||||
@@ -17,8 +18,21 @@ services:
|
||||
"pg_stat_statements.track=all",
|
||||
"-c",
|
||||
"log_min_duration_statement=${POSTGRES_LOG_MIN_DURATION_STATEMENT_MS:-500}",
|
||||
"-c",
|
||||
"shared_buffers=${POSTGRES_SHARED_BUFFERS:-256MB}",
|
||||
"-c",
|
||||
"effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB}",
|
||||
"-c",
|
||||
"work_mem=${POSTGRES_WORK_MEM:-8MB}",
|
||||
"-c",
|
||||
"maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-128MB}",
|
||||
]
|
||||
restart: unless-stopped
|
||||
# 让 PostgreSQL 优雅关闭有足够时间完成检查点;无限制时 OOM 可能拖垮整机。
|
||||
mem_limit: ${POSTGRES_MEM_LIMIT:-1g}
|
||||
cpus: ${POSTGRES_CPUS:-2}
|
||||
shm_size: 512mb
|
||||
stop_grace_period: 60s
|
||||
logging: *json-log-rotation
|
||||
environment:
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
@@ -46,6 +60,10 @@ services:
|
||||
DEBIAN_MIRROR: ${DEBIAN_MIRROR:-mirrors.aliyun.com}
|
||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmmirror.com}
|
||||
restart: unless-stopped
|
||||
# 30s 让后端在 SIGTERM 后完成优雅关闭(HTTP 连接收尾 + 数据库连接池释放)。
|
||||
mem_limit: ${BACKEND_MEM_LIMIT:-512m}
|
||||
cpus: ${BACKEND_CPUS:-1}
|
||||
stop_grace_period: 30s
|
||||
env_file:
|
||||
- .env
|
||||
depends_on:
|
||||
@@ -101,6 +119,9 @@ services:
|
||||
ALPINE_MIRROR: ${ALPINE_MIRROR:-mirrors.aliyun.com}
|
||||
NPM_REGISTRY: ${NPM_REGISTRY:-https://registry.npmmirror.com}
|
||||
restart: unless-stopped
|
||||
mem_limit: ${WEB_MEM_LIMIT:-256m}
|
||||
cpus: ${WEB_CPUS:-0.5}
|
||||
stop_grace_period: 20s
|
||||
logging: *json-log-rotation
|
||||
depends_on:
|
||||
backend:
|
||||
|
||||
@@ -38,3 +38,20 @@ ORDER BY query_start;
|
||||
- `DATABASE_MAX_CONNECTIONS` 按后端实例数总量评估;扩容后端实例时不能简单地每实例增加连接数。
|
||||
- CPU 限额只能防止数据库拖垮整机,不能替代 SQL 优化。
|
||||
- 数据量持续增长后,排行榜和历史统计应迁移到汇总表、缓存或只读副本,不应继续依赖在线全量聚合。
|
||||
|
||||
## 容器资源限制
|
||||
|
||||
Compose 对 postgres 与各服务已配置资源限额,默认值按 2G 内存机器设置,均可在 `.env` 覆盖(见 `.env.server.example` 的 `POSTGRES_*` / `BACKEND_MEM_LIMIT` / `WEB_MEM_LIMIT` 等):
|
||||
|
||||
| 服务 | 限额 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| postgres | `mem_limit` 1g、`cpus` 2、`shm_size` 512mb | `shm_size` 不足会导致并行查询/大排序报错;`stop_grace_period` 60s 保证检查点能完整落盘 |
|
||||
| backend | `mem_limit` 512m、`cpus` 1 | `stop_grace_period` 30s 保证优雅关闭(HTTP 收尾 + 连接池释放)能跑完 |
|
||||
| web | `mem_limit` 256m、`cpus` 0.5 | Caddy 静态服务,低占用 |
|
||||
| dev postgres | 同生产默认 | 仅 postgres 受限;backend/frontend 开发容器不设限,避免 tsx watch / npm install 内存波动被误杀 |
|
||||
|
||||
调整原则:
|
||||
|
||||
- 内存限额不要低于 RSS 峰值的 1.3 倍,否则会触发 OOM 杀容器(`restart: unless-stopped` 会崩溃循环)。
|
||||
- 内存类 PG 参数遵循大致比例:`shared_buffers` ≈ 内存的 1/8~1/4,`effective_cache_size` ≈ 内存的 1/2~3/4,且两者之和不宜超过可用内存的 80%。
|
||||
- 修改限额后 `docker compose config` 会以明文展示最终值,可用它核对插值结果;变更仅对重建/重启的容器生效。
|
||||
|
||||
Reference in New Issue
Block a user