4.9 KiB
单租户 10 万学生容量验证手册
本工具用合成数据验证租户后台学生列表在单租户最多 100000 名学生时的 PostgreSQL 查询形状、cursor 分页和子串搜索。它不会连接 API,直接使用与 GET /api/tenant-admin/students 相同的 SQL 核心和下列索引:
idx_memberships_student_keyset_pageidx_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. 先看计划
默认模式不连接数据库、不写数据:
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=1 且 cleanup.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 指标一起归档。