Files
gongxue-base/docs/refactor/backend-open-items-and-capacity-20260701.md
2026-07-03 22:56:58 +08:00

105 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 后端剩余功能与真实数据容量复核
更新时间2026-07-01
这份文件用于回答“旧题库功能还有哪些没补齐、当前能支撑多少人同时在线刷题、上线前还要做什么”。结论以当前 Supabase/PostgreSQL 新架构为准,旧 PocketBase 项目只作为功能参考和数据迁移来源。
## 功能对齐结论
后端主链路已经覆盖旧题库的核心业务:刷题、顺序/随机/全真模拟、答题判分、错题本、收藏夹、背单词、知识手册、分数线、个人中心、会员权益、订单、优惠券、激活码、题目反馈、勋章、站内通知、题目视频、资料下载、题库/单词/手册/分数线/视频导入、题库导出、租户后台内容管理、学生运营、销售/代理/CRM、分佣、平台 SaaS 租户/套餐/账单/用量/公共题库授权。
多租户底座已经具备商用联调条件租户隔离、Supabase Auth JWT 映射、迁移期 session、RLS 测试、平台/租户/学生三类身份边界、租户自定义角色模板、班级/教师/学生范围权限、字段脱敏、审计日志、私有资源短签名和导入/导出 job 审计均已落地。
两个产品口径已经定稿,不再作为默认待办反复开发:
- 学生头像只支持 `avatarPreset=male/female` 默认资源;不做头像上传、裁剪、第三方头像落库,也不允许租户后台批量导入头像 URL。
- 排行榜接口保留为租户显式开启后的活动能力;默认不开启,学生端默认不请求、不展示,日常学习激励以后台配置勋章自动发放为主。
## 仍需完成
当前“仍需完成”不是旧题库核心功能缺口。刷题、背单词、知识手册、分数线、个人中心、会员/订单、错题/收藏、资料/视频、租户后台、平台 SaaS、公共题库、销售/CRM/分佣等后端主链路已经具备前端联调条件。剩余项主要是上云生产环境、真实三方 provider、真实旧数据人工复核、运维安全和体验增强。
### 上云生产前 P0
1. 真实云端 Auth/JWKS、RLS 和生产配置验收:在预生产/生产执行 `readiness:production``readiness:production:db``smoke:auth:remote``test:rls` 并留档,生产关闭 `x-user-id` 和平台本地 key 兼容入口。
2. 真实旧数据人工复核:正式切换前处理 7 个已支付缺用户订单、22 个缺所属手册章节,并对题目、权益、订单、错题、资料和视频做人工抽样。
3. 真实 provider 联调:阿里云 PNVS 短信认证真实手机号 smoke、微信小程序登录、微信网页登录、QQ 登录、微信支付、支付宝、支付/退款回调域名、官方账单格式抽样。传统阿里云/腾讯云短信 adapter 保留兼容路径;当前生产 readiness 已会阻断 mock/未知短信 provider、OAuth/支付回调非 HTTPS、支付缺 `notifyUrl`、公开配置混入密钥和 active provider 缺 `tenant_secrets`
4. 对象存储生产安全:配置真实 OSS/COS/Supabase Storage bucket、外部 AV/内容安全扫描、CDN 防盗链、转码/CDN 级水印、生命周期策略和恢复演练。API/worker 已会拒绝 local_dev、未知存储 provider、非 HTTPS 公开 URL 和阿里云 OSS 内网直签。
5. 生产容量复测:目标云服务器按 4 核 16G 调参文档设置 PostgreSQL再按 30/50/100 只读和混合读写矩阵复跑,生成 `production-launch-evidence.json` 并通过 `npm run launch:gate`
6. 备份、日志、告警、回滚和安全扫描完成数据库快照、恢复演练、日志告警、Codex Security 真实扫描和上线审批证据。
### 商用增强 P1/P2
1. Taro 侧继续补小程序真机公式/图片混排、题图资源字段化、状态管理、包体优化、小程序支付容器、分享场景和端到端测试。
2. 租户后台继续补更细数据范围 UI、成员批量运营、主题素材库、导入操作体验、导出模板精排、财务复核细节和学习督导触达/效果归因。
3. 平台后台继续补平台在线收款、审计告警升级策略、催缴通知操作台细节、跨租户 BI 和更完整运营消息。
4. 销售/代理继续补真实打款 provider、发票、批量凭证上传、转化预聚合、团队看板和异常调整单。
5. AI 择校继续补真实 AI provider、prompt 版本管理、租户后台配置、PDF 报告 worker 和人工复核流程。
## 本地真实数据压测
### 环境和数据
- 环境Windows + Docker Desktop + 本地 Supabase/PostgreSQL + 本地 API 进程。
- Docker Desktop 当前资源20 CPU、约 62.7GB 内存。这个本机结果会高于常见 4 核 16G 云服务器,不能直接作为生产 SLA。
- 数据库PocketBase 真实导入数据,并已包含前期写入压测产生的练习/答题记录。
- 当前本地迁移库规模19 个租户、74,131 道题、3,722 个平台用户、3,712 个学生资料、1,631 个题目合集、3,120 个练习蓝图、3,519 个单词、2,692 条知识手册条目、81,160 个练习 session、327,925 条答题记录、38,207 条错题、1,501 个内容资源、474 条权益。后续 `db:smoke-seed`、集成测试和压测会继续写入练习/答题/测试租户数据,因此这里按当前本地观察描述,不把每次测试后的瞬时行数当作生产 SLA 口径。
- 排行榜未纳入默认负载,因为产品默认关闭。
### 2026-07-01 08:41 本地真实迁移库 API 进程压测
本轮使用本地 Node API 进程自动启动临时端口,数据库为 Docker Desktop 中的本地 Supabase/PostgreSQL鉴权使用 `PERF_AUTH_MODE=app_session` 的 Bearer session。Docker Desktop 当前分配 20 CPU、约 62.7GB 内存,高于常见 4 核 16G 云服务器;因此这轮是“真实迁移数据 + 本机较高资源”的代码与索引能力观察,不是生产 SLA。
| 场景 | 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 | 结论 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| 只读上线门禁 | 30 | 120s | 0% | 37,520 | 0.00% | 310.34 req/s | 251.08 ms | 388.49 ms | 通过 |
| 混合读写 | 50 | 60s | 10% | 25,047 | 0.00% | 410.49 req/s | 237.41 ms | 344.51 ms | 舒适 |
| 混合读写 | 100 | 60s | 8% | 24,116 | 0.00% | 393.56 req/s | 437.37 ms | 533.63 ms | 可用上沿 |
| 混合读写 | 150 | 60s | 6% | 22,864 | 0.00% | 371.29 req/s | 633.46 ms | 759.62 ms | 压力区 |
混合读写包含真实刷题闭环:创建练习 session、拉取 session detail、提交答案、交卷、读取报告。150 worker 仍保持 0 错误,但 P95 已超过 600ms当前本机可把 100 worker 混合读写视为可用上沿,把 50 worker 混合读写视为舒适区。
同轮 `LAUNCH_SMOKE_AUTH_MODE=app_session npm run smoke:launch-persona -- --write docs/refactor/launch-artifacts/launch-persona-smoke.json --write-md docs/refactor/launch-artifacts/launch-persona-smoke.md` 已通过,并生成稳定上线证据 artifact。角色旅程覆盖普通学生 SVIP 后刷题、收藏、错题复习入口,租户管理员 dashboard/主题/学生/销售转化入口,平台管理员租户/套餐/审计入口,以及学生越权后台和跨租户访问拒绝。
### 2026-07-01 07:59 真实迁移库 Docker API 受限资源复核
本轮使用 `npm run perf:api:docker-4c16g`API 容器限制为 2 CPU/4G、`DB_POOL_MAX=10`、关闭 legacy `x-user-id` 和平台本地 key压测鉴权使用 `PERF_AUTH_MODE=app_session` 的 Bearer session。数据库仍为本机 Docker Desktop Supabase/PostgreSQL未限制为 4 核 16G因此结果更接近“受限 API 容器 + 本机数据库”的预生产观察,不是最终云服务器 SLA。
历史受限容器压测曾暴露一个真实并发缺陷50 worker 混合读写中,交卷触发自动勋章发放时撞到 `user_badges_tenant_id_legacy_id_key`,产生 1 个 500。已修复为自动勋章只使用 `(tenant_id, user_id, badge_id)` 做业务幂等,不再写入自动生成 `legacy_id`;并新增 `scripts/auto-badge-concurrency-test.js`20 个并发触发同一学生同一勋章时只生成 1 条 `user_badges`
| 场景 | 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 | 结论 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| 只读上线门禁 | 30 | 120s | 0% | 36,800 | 0.00% | 305.59 req/s | 241.46 ms | 351.17 ms | 通过 |
| 混合读写 | 50 | 60s | 10% | 24,120 | 0.00% | 398.79 req/s | 231.28 ms | 325.94 ms | 舒适 |
| 混合读写 | 100 | 60s | 8% | 22,462 | 0.00% | 370.86 req/s | 445.26 ms | 532.32 ms | 可用但延迟偏高 |
| 混合读写 | 150 | 60s | 6% | 20,708 | 0.00% | 340.74 req/s | 689.67 ms | 833.08 ms | 压力区 |
混合读写包含真实刷题闭环:创建练习 session、拉取 session detail、提交答案、交卷、读取报告。
同轮 `npm run smoke:taro:h5:interaction` 已通过 32/32覆盖学生端核心旅程、租户后台真实写操作和平台后台真实写操作`npm run smoke:launch-persona` 已通过,覆盖普通学生 SVIP 后刷题、收藏、错题复习入口,租户管理员 dashboard/主题/学生/销售转化入口,平台管理员租户/套餐/审计入口,以及学生越权后台和跨租户访问拒绝。
### 在线人数折算
压测 worker 是无停顿请求流,不等于真实在线学生。刷题学生会读题、思考、翻页和等待网络,前端完成后还需要用真实埋点计算“单个活跃学生平均 RPS”。
按目前常见页面节奏先用 `0.05 到 0.2 req/s/人` 粗略折算。本轮本地 API 进程压测的在线吞吐观察为:
- 50 worker 舒适场景 410.49 req/s约等于 2,052 到 8,210 名活跃在线学生的请求吞吐。
- 100 worker 可用上沿场景 393.56 req/s约等于 1,968 到 7,871 名活跃在线学生的请求吞吐。
- 150 worker 压力场景 371.29 req/s约等于 1,856 到 7,426 名活跃在线学生的请求吞吐。
当前本地结论:在真实迁移数据和本机较高资源下,后端刷题读写链路的舒适观察区间约为 410 req/s折算约 2,052 到 8,210 名活跃在线学生100 worker 仍满足混合写入观察线但 P95 已超过 400ms可作为当前本机可用上沿150 worker 仍 0 错误但 P95 已超过 600ms视为压力区不建议作为生产承诺。正式对外容量必须以云端 4 核 16G、PostgreSQL shared-host 参数、真实对象存储/CDN 和前端真实请求节奏复测为准。
### 2026-07-01 Docker API + DB 显式受限复核
本轮使用同一压测入口,但显式设置 `BENCHMARK_LIMIT_DB_RESOURCES=true`API 容器限制为 2 CPU/4GSupabase PostgreSQL 容器限制为 2 CPU/8G`DB_POOL_MAX=10`。PostgreSQL 参数仍是本地默认值,没有应用 `docs/refactor/postgresql-4c16g-tuning.md` 的 shared-host profile。
| 场景 | 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 | 结论 |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| 只读上线门禁 | 30 | 120s | 0% | 8,397 | 0.00% | 69.48 req/s | 1183.29 ms | 1697.59 ms | 失败,延迟超过门禁 |
| 混合读写 | 50 | 60s | 10% | 6,640 | 0.00% | 109.61 req/s | 996.01 ms | 1303.45 ms | 失败,延迟超过观察线 |
| 混合读写 | 100 | 60s | 8% | 6,381 | 0.00% | 104.13 req/s | 1705.51 ms | 2098.41 ms | 压力区 |
| 混合读写 | 150 | 60s | 6% | 5,211 | 0.00% | 83.23 req/s | 3006.71 ms | 3699.64 ms | 压力区 |
这组结果说明:代码在更严格资源下仍保持 0 错误,但默认 PostgreSQL 参数无法支撑上线延迟门禁。正式对外容量必须等 4 核 16G 云服务器部署、PostgreSQL shared-host 调参、`pg_stat_statements` 和慢 SQL 观察完成后复跑。没有云端复测前,不再把本地 07:59 API-only 观察值当生产容量承诺只保留为乐观参考06:53 DB 受限结果则作为未调参下限参考。