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

4.9 KiB
Raw Blame History

单租户 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_idraw_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. 先看计划

默认模式不连接数据库、不写数据:

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 中人为保留的基准夹具。

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=1cleanup.deletedUsers=250

3. 生成 10 万行并跑基准

run 会保留夹具,便于重复采样或查看查询计划:

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

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. 重复基准

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. 清理

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 指标一起归档。