forked from wangziqi/gongxue-base
docs: update launch capacity and postgres tuning
This commit is contained in:
@@ -43,7 +43,7 @@
|
||||
- 环境:Windows + Docker Desktop + 本地 Supabase/PostgreSQL + 本地 API 进程。
|
||||
- Docker Desktop 当前资源:20 CPU、约 62.7GB 内存。这个本机结果会高于常见 4 核 16G 云服务器,不能直接作为生产 SLA。
|
||||
- 数据库:PocketBase 真实导入数据,并已包含前期写入压测产生的练习/答题记录。
|
||||
- 当前本地迁移库规模:约 7.4 万道题、3,700 个用户、1,600 个题目合集、3,100 个练习蓝图、3,500 个单词、2,600 条知识手册、25.2 万条答题记录、3.8 万条错题、468 条权益。后续 `db:smoke-seed`、集成测试和压测会继续写入练习/答题/测试租户数据,因此这里按当前本地观察描述,不把每次测试后的瞬时行数当作生产 SLA 口径。
|
||||
- 当前本地迁移库规模:13 个租户、约 7.4 万道题、3,710 个用户、1,619 个题目合集、3,114 个练习蓝图、3,513 个单词、2,686 条知识手册条目、6.0 万练习 session、26.4 万条答题记录、3.8 万条错题、1,477 个内容资源、468 条权益。后续 `db:smoke-seed`、集成测试和压测会继续写入练习/答题/测试租户数据,因此这里按当前本地观察描述,不把每次测试后的瞬时行数当作生产 SLA 口径。
|
||||
- 排行榜未纳入默认负载,因为产品默认关闭。
|
||||
|
||||
### 2026-07-01 真实迁移库 Docker API 受限资源复核
|
||||
@@ -54,10 +54,10 @@
|
||||
|
||||
| 场景 | 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 | 结论 |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
|
||||
| 只读上线门禁 | 30 | 120s | 0% | 44,692 | 0.00% | 371.62 req/s | 188.91 ms | 275.79 ms | 通过 |
|
||||
| 混合读写 | 50 | 60s | 10% | 26,815 | 0.00% | 444.49 req/s | 204.08 ms | 268.88 ms | 舒适 |
|
||||
| 混合读写 | 100 | 60s | 8% | 25,950 | 0.00% | 428.30 req/s | 375.38 ms | 447.47 ms | 接近舒适区上沿 |
|
||||
| 混合读写 | 150 | 60s | 6% | 23,970 | 0.00% | 394.80 req/s | 574.37 ms | 696.35 ms | 压力区 |
|
||||
| 只读上线门禁 | 30 | 120s | 0% | 42,982 | 0.00% | 357.28 req/s | 192.25 ms | 287.93 ms | 通过 |
|
||||
| 混合读写 | 50 | 60s | 10% | 26,086 | 0.00% | 431.78 req/s | 207.10 ms | 283.57 ms | 舒适 |
|
||||
| 混合读写 | 100 | 60s | 8% | 25,242 | 0.00% | 417.03 req/s | 383.30 ms | 464.22 ms | 接近舒适区上沿 |
|
||||
| 混合读写 | 150 | 60s | 6% | 24,201 | 0.00% | 398.22 req/s | 567.89 ms | 706.09 ms | 压力区 |
|
||||
|
||||
混合读写包含真实刷题闭环:创建练习 session、拉取 session detail、提交答案、交卷、读取报告。
|
||||
|
||||
@@ -69,10 +69,10 @@
|
||||
|
||||
按目前常见页面节奏先用 `0.05 到 0.2 req/s/人` 粗略折算:
|
||||
|
||||
- 50 worker 舒适场景 444 req/s,约等于 2,220 到 8,880 名活跃在线学生的请求吞吐。
|
||||
- 100 worker 上沿场景 428 req/s,约等于 2,140 到 8,560 名活跃在线学生的请求吞吐。
|
||||
- 150 worker 压力场景 395 req/s,约等于 1,975 到 7,900 名活跃在线学生的请求吞吐。
|
||||
- 50 worker 舒适场景 432 req/s,约等于 2,160 到 8,640 名活跃在线学生的请求吞吐。
|
||||
- 100 worker 上沿场景 417 req/s,约等于 2,085 到 8,340 名活跃在线学生的请求吞吐。
|
||||
- 150 worker 压力场景 398 req/s,约等于 1,990 到 7,960 名活跃在线学生的请求吞吐。
|
||||
|
||||
当前本地结论:在受限 API 容器下,后端真实刷题读写链路的舒适观察区间约为 428 到 444 req/s,折算约 2,100 到 8,900 名活跃在线学生;150 worker 仍 0 错误但 P95 已接近 600ms,视为压力区,不建议作为生产承诺。同日本地 API 进程 30 worker/30 秒/10% 写入观察到 15,864 请求、0 错误、513.56 req/s、P95 113.97ms;受限 API 容器会明显压低上沿,因此上线承诺仍以云端受限资源复测为准。
|
||||
当前本地结论:在受限 API 容器下,后端真实刷题读写链路的舒适观察区间约为 417 到 432 req/s,折算约 2,100 到 8,600 名活跃在线学生;150 worker 仍 0 错误但 P95 已接近 600ms,视为压力区,不建议作为生产承诺。同日本地 API 进程 30 worker/30 秒/10% 写入观察到 15,864 请求、0 错误、513.56 req/s、P95 113.97ms;受限 API 容器会明显压低上沿,因此上线承诺仍以云端受限资源复测为准。
|
||||
|
||||
正式对外容量必须等 4 核 16G 云服务器部署后复跑。保守规划时,生产首版建议先按本地折算值的 30% 到 50% 做容量承诺,等云端压测、CDN、对象存储和真实前端埋点完成后再上调。
|
||||
正式对外容量必须等 4 核 16G 云服务器部署后复跑。保守规划时,生产首版建议先按本地折算值的 30% 到 50% 做容量承诺,约 630 到 4,300 名活跃在线学生,等云端压测、CDN、对象存储和真实前端埋点完成后再上调。
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
- 已补 `npm run launch:gate` 生产上线证据门禁和 `docs/refactor/production-launch-evidence.template.json` 模板;最终切换前必须把 readiness、远程 Auth、RLS、PostgreSQL 4c16g 严格调参证据、生产 dry-run、导入校验、`pb:import:sample` 业务抽样、真实数据 API 只读压测、真实数据混合读写压测、API/worker/Taro、运行时审计、`security:repo`、真实 `@codex-security`、备份/回滚/真实抽样/生产 provider 等证据填入本地 `production-launch-evidence.json` 并通过门禁。当前 Codex 环境未暴露可调用的 `@codex-security` 扫描工具时,该项只能标为待补,不能伪造完成。
|
||||
- 确认数据库迁移流程、备份恢复、日志、告警。
|
||||
- 准备 API 容器部署和 Supabase 云端/自托管连接方案。
|
||||
- 已补 `npm run perf:api:local`、`npm run perf:summary`、`npm run perf:postgres:evidence`、`npm run perf:postgres:sql`、`npm run smoke:launch-persona`、`npm run smoke:taro:h5`、`npm run smoke:taro:h5:interaction`、`node scripts/taro-api-contract-test.js`、`node scripts/taro-persona-contract-test.js` 和 `docs/refactor/performance-benchmark-runbook.md`,可在本地或云端对真实迁移数据做只读门禁、混合读写容量观察、PostgreSQL 4c16g profile 调参证据、三类后端角色旅程烟测、三类 Taro 前端角色旅程契约、H5 发布目录启动烟测、真实浏览器关键点击烟测和前端 API 契约检查。2026-07-01 04:44 受限 API 容器真实迁移库复核中,30 worker/120s 只读为 44,692 请求、0 错误、371.62 req/s、P95 188.91ms、P99 275.79ms;50 worker/60s/10% 写入为 26,815 请求、0 错误、444.49 req/s、P95 204.08ms、P99 268.88ms;100 worker/60s/8% 写入为 25,950 请求、0 错误、428.30 req/s、P95 375.38ms、P99 447.47ms;150 worker/60s/6% 写入为 23,970 请求、0 错误、394.80 req/s、P95 574.37ms、P99 696.35ms。受限容器系列压测曾抓到自动勋章并发发放唯一键冲突,已修复并新增 `scripts/auto-badge-concurrency-test.js`。当前 Docker Desktop 给了 20 CPU/约 62.7GB 内存,但 API 容器限制为 2 CPU/4G,舒适观察区暂按 50 到 100 个无停顿 worker 估算,150 worker 已是压力区;按单学生 0.05 到 0.2 req/s 粗略折算约为 2,100 到 8,900 名活跃在线学生的本机吞吐观察区间,正式容量仍以上云 4 核 16G 复测为准。
|
||||
- 已补 `npm run perf:api:local`、`npm run perf:summary`、`npm run perf:postgres:evidence`、`npm run perf:postgres:sql`、`npm run smoke:launch-persona`、`npm run smoke:taro:h5`、`npm run smoke:taro:h5:interaction`、`node scripts/taro-api-contract-test.js`、`node scripts/taro-persona-contract-test.js` 和 `docs/refactor/performance-benchmark-runbook.md`,可在本地或云端对真实迁移数据做只读门禁、混合读写容量观察、PostgreSQL 4c16g profile 调参证据、三类后端角色旅程烟测、三类 Taro 前端角色旅程契约、H5 发布目录启动烟测、真实浏览器关键点击烟测和前端 API 契约检查。2026-07-01 05:05 受限 API 容器真实迁移库复核中,30 worker/120s 只读为 42,982 请求、0 错误、357.28 req/s、P95 192.25ms、P99 287.93ms;50 worker/60s/10% 写入为 26,086 请求、0 错误、431.78 req/s、P95 207.10ms、P99 283.57ms;100 worker/60s/8% 写入为 25,242 请求、0 错误、417.03 req/s、P95 383.30ms、P99 464.22ms;150 worker/60s/6% 写入为 24,201 请求、0 错误、398.22 req/s、P95 567.89ms、P99 706.09ms。受限容器系列压测曾抓到自动勋章并发发放唯一键冲突,已修复并新增 `scripts/auto-badge-concurrency-test.js`。当前 Docker Desktop 给了 20 CPU/约 62.7GB 内存,但 API 容器限制为 2 CPU/4G,舒适观察区暂按 50 到 100 个无停顿 worker 估算,150 worker 已是压力区;按单学生 0.05 到 0.2 req/s 粗略折算约为 2,100 到 8,600 名活跃在线学生的本机吞吐观察区间,正式容量仍以上云 4 核 16G 复测为准。
|
||||
- 当前本地 PostgreSQL evidence 仍提示 `jit=on`、`statement_timeout=0`、`idle_in_transaction_session_timeout=0`、`lock_timeout=0`;上云后必须按 `docs/refactor/postgresql-4c16g-tuning.md` 调整参数,执行 `PG_TUNING_PROFILE=shared-host npm run perf:postgres:evidence -- --strict --json` 并通过后,再按 6/30/50/100 阶梯并发复跑容量报告并归档到本地上线证据。
|
||||
- 本轮剩余功能和容量复核已经整理到 `docs/refactor/backend-open-items-and-capacity-20260701.md`。后续不要再把学生头像上传或默认排行榜当作待办;头像只保留男女预设,排行榜仅作为租户显式开启后的活动能力。
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ npm run perf:api:local
|
||||
npm run launch:gate
|
||||
```
|
||||
|
||||
`launch:gate` 会强制检查一条真实数据读路径压测证据:
|
||||
`launch:gate` 会强制检查真实数据只读压测和混合读写压测两条证据。只读证据用于基础上线门禁:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -285,6 +285,37 @@ npm run perf:summary -- --input docs/refactor/performance-reports/api-benchmark-
|
||||
|
||||
使用 `--allow-writes` 时,摘要工具输出 `capacityObservation`,不输出 `launchGateCheck`;不要把写入场景误填进生产上线门禁的 `performance.api-real-data-read`。
|
||||
|
||||
更高的 50/100 并发、写入混合场景和容量结论仍应作为人工容量报告归档;门禁只负责挡住明显不达标的基础读路径。
|
||||
混合读写证据用于确认“创建练习 session -> 拉题 -> 答题 -> 交卷 -> 报告”的真实写入链路在上线容量基线内:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "performance.api-real-data-mixed",
|
||||
"status": "pass",
|
||||
"command": "PERF_START_SERVER=false PERF_API_BASE=https://api.example.com PERF_DURATION_SECONDS=120 PERF_CONCURRENCY=50 PERF_RAMP_SECONDS=15 PERF_INCLUDE_WRITES=true PERF_PRACTICE_FLOW_RATIO=0.1 PERF_AUTH_MODE=app_session npm run perf:api:local > docs/refactor/launch-artifacts/api-real-data-mixed-benchmark.log",
|
||||
"completedAt": "2026-06-30T10:49:00+08:00",
|
||||
"artifact": "launch-artifacts/api-real-data-mixed-benchmark.log",
|
||||
"summary": {
|
||||
"errors": 0,
|
||||
"errorRate": 0,
|
||||
"p95Ms": 0,
|
||||
"p99Ms": 0,
|
||||
"concurrency": 50,
|
||||
"durationSeconds": 120,
|
||||
"includeWrites": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
混合读写上线门槛:
|
||||
|
||||
- `errors = 0`
|
||||
- `errorRate <= 0.001`
|
||||
- `p95Ms <= 500`
|
||||
- `p99Ms <= 1200`
|
||||
- `concurrency >= 50`
|
||||
- `durationSeconds >= 60`
|
||||
- `includeWrites = true`
|
||||
|
||||
更高的 100/150 并发和更长时间压测仍应作为人工容量报告归档;门禁负责挡住基础读路径和刷题写入闭环明显不达标的情况。
|
||||
|
||||
证据中只记录报告路径、并发矩阵、P95/P99、错误率和结论,不保存真实 token、支付密钥、用户隐私或完整响应。
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- PostgreSQL 官方 WAL/Checkpoint:https://www.postgresql.org/docs/current/runtime-config-wal.html
|
||||
- PostgreSQL 官方 Connections:https://www.postgresql.org/docs/current/runtime-config-connection.html
|
||||
|
||||
说明:postgresqlco.nf 的页面可作为参数分类和调参入口参考;具体参数语义、重启要求和风险以 PostgreSQL 官方文档为准。当前 Codex 环境访问 `https://postgresqlco.nf/tuning-guide` 会返回 403,因此落地值不直接抓取该站页面,而是把它作为导航来源,并以 PostgreSQL 官方文档和本项目真实压测结果共同校验。
|
||||
说明:postgresqlco.nf 的 tuning guide 适合作为 `postgresql.conf` 参数分类和调参入口参考;具体参数语义、重启要求、风险边界和版本差异仍以 PostgreSQL 官方文档为准。当前 Codex 环境直接访问 `https://postgresqlco.nf/tuning-guide` 会返回 403,因此落地值不直接抓取该站页面,而是把它作为导航来源,并以 PostgreSQL 官方文档、本项目真实压测结果和上线可观测性共同校验。
|
||||
|
||||
## 适用前提
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
| `idle_in_transaction_session_timeout` | `60s` | `60s` | 防止后台或脚本长事务占锁 |
|
||||
| `statement_timeout` | `30s` | `30s` | API 请求不应长期占用数据库;导入脚本用会话级覆盖 |
|
||||
| `lock_timeout` | `5s` | `5s` | 防止普通请求长时间等锁 |
|
||||
| `temp_file_limit` | `4GB` | `8GB` | 给报表/导入留出空间,同时避免异常 SQL 无限落临时文件 |
|
||||
| `log_temp_files` | `128MB` | `128MB` | 记录大临时文件,定位排序/哈希溢出和缺索引问题 |
|
||||
| `log_checkpoints` | `on` | `on` | 记录 checkpoint,便于把延迟波动和 WAL/checkpoint 压力关联起来 |
|
||||
| `track_io_timing` | `on` | `on` | 压测和灰度期定位读写 I/O 耗时 |
|
||||
| `track_wal_io_timing` | `on` | `on` | 定位答题、订单、导入等写入场景的 WAL I/O 压力 |
|
||||
| `max_parallel_workers_per_gather` | `1` | `2` | 4 核 OLTP/API 场景避免单个查询吃掉过多并行 worker |
|
||||
|
||||
## 证据采集脚本
|
||||
|
||||
@@ -75,6 +81,8 @@ PG_TUNING_PROFILE=shared-host npm run perf:postgres:evidence -- --strict --json
|
||||
|
||||
- `jit=off`。
|
||||
- `statement_timeout`、`idle_in_transaction_session_timeout`、`lock_timeout` 不得为 0。
|
||||
- `track_io_timing=on`、`track_wal_io_timing=on`、`log_checkpoints=on`。
|
||||
- `temp_file_limit`、`log_temp_files` 和 `max_parallel_workers_per_gather` 必须落在 profile 范围内。
|
||||
- 所有 profile 参数必须在允许范围内。
|
||||
- `pending_restart` 必须为 0。
|
||||
- `pg_stat_statements` 必须可用。
|
||||
@@ -122,7 +130,13 @@ where name in (
|
||||
'log_min_duration_statement',
|
||||
'idle_in_transaction_session_timeout',
|
||||
'statement_timeout',
|
||||
'lock_timeout'
|
||||
'lock_timeout',
|
||||
'temp_file_limit',
|
||||
'log_temp_files',
|
||||
'log_checkpoints',
|
||||
'track_io_timing',
|
||||
'track_wal_io_timing',
|
||||
'max_parallel_workers_per_gather'
|
||||
)
|
||||
order by name;
|
||||
```
|
||||
@@ -154,10 +168,16 @@ alter system set log_min_duration_statement = '500ms';
|
||||
alter system set idle_in_transaction_session_timeout = '60s';
|
||||
alter system set statement_timeout = '30s';
|
||||
alter system set lock_timeout = '5s';
|
||||
alter system set temp_file_limit = '4GB';
|
||||
alter system set log_temp_files = '128MB';
|
||||
alter system set log_checkpoints = 'on';
|
||||
alter system set track_io_timing = 'on';
|
||||
alter system set track_wal_io_timing = 'on';
|
||||
alter system set max_parallel_workers_per_gather = '1';
|
||||
select pg_reload_conf();
|
||||
```
|
||||
|
||||
以下参数需要重启 PostgreSQL 才会生效:`max_connections`、`shared_buffers`、`wal_buffers`。执行后用下面语句确认:
|
||||
以下参数需要重启 PostgreSQL 才会生效:`max_connections`、`shared_buffers`、`wal_buffers`。`track_io_timing`、`track_wal_io_timing`、`log_checkpoints`、`log_temp_files`、`temp_file_limit`、`max_parallel_workers_per_gather` 通常可 reload,但仍以后续 `pending_restart` 检查为准。执行后用下面语句确认:
|
||||
|
||||
```sql
|
||||
select name, setting, unit, pending_restart
|
||||
@@ -278,6 +298,12 @@ alter system reset log_min_duration_statement;
|
||||
alter system reset idle_in_transaction_session_timeout;
|
||||
alter system reset statement_timeout;
|
||||
alter system reset lock_timeout;
|
||||
alter system reset temp_file_limit;
|
||||
alter system reset log_temp_files;
|
||||
alter system reset log_checkpoints;
|
||||
alter system reset track_io_timing;
|
||||
alter system reset track_wal_io_timing;
|
||||
alter system reset max_parallel_workers_per_gather;
|
||||
select pg_reload_conf();
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user