Files
gongxue-base/docs/refactor/tenant-student-capacity-runbook.md
2026-07-12 19:26:57 +08:00

107 lines
4.9 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.

# 单租户 10 万学生容量验证手册
本工具用合成数据验证租户后台学生列表在单租户最多 100000 名学生时的 PostgreSQL 查询形状、cursor 分页和子串搜索。它不会连接 API直接使用与 `GET /api/tenant-admin/students` 相同的 SQL 核心和下列索引:
- `idx_memberships_student_keyset_page`
- `idx_platform_users_identity_search_trgm`
## 安全边界
- 只能用于 `local` / `test` / `ci` 数据库,且 `app_private.environment_safety.allow_destructive_tests` 必须为 `true`
- 任何写入、基准或清理模式都必须显式传入 `SMOKE_SEED_LOCAL_OR_CI_ONLY`
- 租户 slug 必须以 `capacity-test-` 开头。如果同名租户没有匹配的 `metadata.capacityHarness` 标记,工具会拒绝使用它。
- 合成用户同时使用 `legacy_id``raw_profile.capacityHarness` 标记。清理前如果发现真实 `auth_user_id`、其他租户 membership、租户 owner 或专用租户中的非 harness membership工具会拒绝操作。
- 禁止使用 `tikupro-pg` 或任何生产数据库。当前本机 `127.0.0.1:5432` 映射到 `tikupro-pg`,因此工具也会对 localhost/loopback 的 5432 端口在连接前硬拒绝。本工具的本地结果 is not a production SLA。
不要为了跑工具而在现有服务器数据库上修改环境标记。应该新建专用的非生产 PostgreSQL/Supabase 实例,运行全部迁移,再设置测试环境标记。
## 1. 先看计划
默认模式不连接数据库、不写数据:
```bash
npm run perf:tenant-students:plan
```
如果希望在计划中显示脱敏后的 host / port / database / user可以同时提供 `DATABASE_URL`;工具不会输出密码。
## 2. 小规模 smoke
以专用隔离库为例smoke 使用独立的 `capacity-test-students-smoke` 租户生成 250 名学生,执行 5 组查询、写出 JSON/Markdown 证据,然后在成功或失败路径清理专用租户和合成用户。它不会清理 `capacity-test-students-100k` 中人为保留的基准夹具。
```bash
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres' \
npm run test:tenant-students:capacity:smoke
```
报告默认保存到已忽略的 `docs/refactor/performance-reports/`。smoke 返回后应确认 `cleanup.deletedTenant=1``cleanup.deletedUsers=250`
## 3. 生成 10 万行并跑基准
`run` 会保留夹具,便于重复采样或查看查询计划:
```bash
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres' \
npm run perf:tenant-students:run -- \
--count=100000 \
--batch-size=10000 \
--iterations=20 \
--warmup-iterations=3 \
--confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY
```
写入是 set-based 的 `generate_series` + UPSERT每批在独立事务中完成。同一个 count 可重复执行;如果已有夹具行数高于新 count工具会要求先清理避免隐式删数据。
正式上线证据应使用一次性 `evidence` 模式,它会在同一个受保护流程中完成 seed、benchmark、cleanup并把清理结果与四类残留计数写入同一份 JSON
```bash
DATABASE_URL='<target-spec-isolated-clone-url>' \
npm run perf:tenant-students:evidence -- \
--count=100000 \
--batch-size=10000 \
--iterations=20 \
--warmup-iterations=3 \
--confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY
```
`evidence` 模式成功时必须包含 `cleanup.cleanupVerified=true`,且 `remaining.tenants/platformUsers/memberships/profiles` 全部为 `0`
每组证据包含:
- 实际 `platform_users` / `tenant_memberships` / `student_profiles` 行数。
- 工具内部记录的 seed / benchmark / cleanup / total 阶段耗时。
- 首页和约 90% 深度 cursor 页。
- 姓名、手机号、email substring 搜索。
- 应用端观测 P50/P95以及每组 SQL 的 `EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)`
- 实际使用的 plan node、index name、shared/local/temp buffer 摘要与完整 JSON plan。
## 4. 重复基准
```bash
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres' \
npm run perf:tenant-students:benchmark -- \
--iterations=30 \
--confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY
```
深 cursor 使用约 90% 位置的真实 `(created_at, membership_id)` 锚点,不使用 OFFSET 制造查询。
## 5. 清理
```bash
DATABASE_URL='postgresql://postgres:postgres@127.0.0.1:55432/postgres' \
npm run perf:tenant-students:cleanup -- \
--confirm=SMOKE_SEED_LOCAL_OR_CI_ONLY
```
清理只会命中:
- `slug=capacity-test-students-100k` 且带匹配 `metadata.capacityHarness` 的专用租户。
- `raw_profile.capacityHarness.namespace=tiku.student-capacity.v1` 且 tenant slug 相同的合成用户。
自定义租户名时,六个命令都必须传入同一个 `--tenant-slug=capacity-test-...`
## 验收口径
这个工具首先是数据量和查询计划验证,不应单独用它承诺线上 SLA。正式验收还需要在与生产同规格的非生产环境复跑并与 API 并发压测、PostgreSQL 调优证据、连接池和云盘 I/O 指标一起归档。