194 lines
6.1 KiB
Markdown
194 lines
6.1 KiB
Markdown
# Genarrative 作品列表 K6 压测
|
||
|
||
本目录用于对“作品列表/公开广场”读接口做本地压测。数据源来自私有 SpacetimeDB migration,但提取脚本只输出作品 profile 白名单表,并对用户、作者、作品号、asset id 等标识做稳定映射。
|
||
|
||
## 文件
|
||
|
||
- `extract-works-list-data.mjs`:从 migration JSON 提取作品列表压测数据;本地输出也会脱敏路由 ID,因此默认用于列表接口压测,详情接口需先把同一份脱敏数据导入目标环境。
|
||
- `k6-works-list.js`:K6 压测脚本。
|
||
- `data/spacetime-migration-7.local.json`:本地私有原始数据副本,已被 `.gitignore` 忽略,不要提交。
|
||
- `data/works-list.local.json`:本地脱敏压测数据,已被 `.gitignore` 忽略,不要提交。
|
||
- `data/works-list.sample.json`:可提交的少量脱敏样例。
|
||
|
||
## 数据边界
|
||
|
||
允许导入的表:
|
||
|
||
- `puzzle_work_profile`
|
||
- `custom_world_profile`
|
||
- `match3d_work_profile`
|
||
- `square_hole_work_profile`
|
||
- `big_fish_work_profile`
|
||
- `visual_novel_work_profile`
|
||
|
||
明确不导入:
|
||
|
||
- 账号/认证:`user_account`、`auth_identity`、`refresh_session`、`auth_store_snapshot`
|
||
- 钱包/邀请:`profile_wallet_ledger`、`profile_redeem_*`、`profile_invite_*`
|
||
- 游玩历史/埋点/存档:`public_work_play_daily_stat`、`profile_played_world`、`puzzle_runtime_run`、`profile_save_archive`、`runtime_snapshot`
|
||
- AI 任务过程:`ai_task`、`ai_task_stage`、`ai_text_chunk`
|
||
- asset 二进制:`asset_object`、`asset_entity_binding`
|
||
|
||
提取脚本会移除 `source_session_id` / `source_agent_session_id` 等会话派生字段;这些字段不属于作品列表卡片压测必要字段。
|
||
|
||
## 重新提取数据
|
||
|
||
从仓库根目录执行:
|
||
|
||
```bash
|
||
npm run loadtest:extract-works -- \
|
||
--input scripts/loadtest/data/spacetime-migration-7.local.json \
|
||
--output scripts/loadtest/data/works-list.local.json \
|
||
--sample-output scripts/loadtest/data/works-list.sample.json
|
||
```
|
||
|
||
也可以直接执行:
|
||
|
||
```bash
|
||
node scripts/loadtest/extract-works-list-data.mjs \
|
||
--input scripts/loadtest/data/spacetime-migration-7.local.json \
|
||
--output scripts/loadtest/data/works-list.local.json \
|
||
--sample-output scripts/loadtest/data/works-list.sample.json
|
||
```
|
||
|
||
当前 local 全量提取结果:
|
||
|
||
- `puzzle_work_profile`: 80
|
||
- `custom_world_profile`: 1
|
||
- `match3d_work_profile`: 0
|
||
- `normalizedWorks`: 81
|
||
|
||
当前可提交 sample 结果:
|
||
|
||
- `puzzle_work_profile`: 3
|
||
- `custom_world_profile`: 1
|
||
- `match3d_work_profile`: 0
|
||
- `normalizedWorks`: 4
|
||
|
||
## 真实接口
|
||
|
||
已从 `server-rs/crates/api-server/src/app.rs` 确认的读接口:
|
||
|
||
公开接口,无需 Bearer token:
|
||
|
||
- `GET /api/runtime/puzzle/gallery`
|
||
- `GET /api/runtime/puzzle/gallery/{profile_id}`
|
||
- `GET /api/runtime/custom-world-gallery`
|
||
- `GET /api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}`
|
||
- `GET /api/runtime/custom-world-gallery/by-code/{code}`
|
||
|
||
需要 Bearer token 的个人作品列表接口:
|
||
|
||
- `GET /api/runtime/puzzle/works`
|
||
- `GET /api/runtime/puzzle/works/{profile_id}`
|
||
- `GET /api/runtime/custom-world/works`
|
||
|
||
K6 脚本默认只跑公开列表接口;传入 `AUTH_TOKEN` 后会额外跑需要登录态的个人作品列表接口。当前真实列表 handler 未暴露分页/排序 query 参数,因此脚本不追加 `limit/offset`;若后续接口增加分页参数,再在 K6 中补随机分页。
|
||
|
||
详情接口默认不压测,因为本地数据中的 `profile_id` / `owner_user_id` 已脱敏,直接请求未导入脱敏数据的目标服务会 404。只有在目标环境已导入同一份脱敏数据,或改用真实 ID 本地文件时,才设置 `DETAIL_RATIO` 大于 0;详情请求不把 404 视为成功。
|
||
|
||
## 启动服务
|
||
|
||
按项目约定启动本地 dev 栈:
|
||
|
||
```bash
|
||
npm run dev
|
||
```
|
||
|
||
注意端口可能漂移。以启动日志中的实际 api-server 端口为准,然后传给 K6:
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:<actual-api-port> npm run loadtest:k6:works -- --summary-trend-stats="avg,min,med,p(90),p(95),p(99),max"
|
||
```
|
||
|
||
## Smoke
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:8787 \
|
||
WORKS_DATA=scripts/loadtest/data/works-list.local.json \
|
||
SCENARIO=smoke \
|
||
DETAIL_RATIO=0 \
|
||
npm run loadtest:k6:works
|
||
```
|
||
|
||
默认:1 VU / 30s。
|
||
|
||
## Baseline
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:8787 \
|
||
WORKS_DATA=scripts/loadtest/data/works-list.local.json \
|
||
SCENARIO=baseline \
|
||
VUS=10 \
|
||
DURATION=3m \
|
||
DETAIL_RATIO=0 \
|
||
npm run loadtest:k6:works
|
||
```
|
||
|
||
默认阈值:
|
||
|
||
- `http_req_failed < 1%`
|
||
- `http_req_duration p95 < 800ms`
|
||
- `http_req_duration p99 < 1500ms`
|
||
- `works_list_shape_error_rate < 1%`
|
||
|
||
## Spike
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:8787 \
|
||
WORKS_DATA=scripts/loadtest/data/works-list.local.json \
|
||
SCENARIO=spike \
|
||
START_RPS=5 \
|
||
PEAK_RPS=100 \
|
||
HOLD=2m \
|
||
DETAIL_RATIO=0 \
|
||
npm run loadtest:k6:works
|
||
```
|
||
|
||
默认阈值:
|
||
|
||
- `http_req_failed < 5%`
|
||
- `http_req_duration p95 < 2000ms`
|
||
- `works_list_shape_error_rate < 5%`
|
||
|
||
## 带登录态压测个人作品列表
|
||
|
||
先通过本地登录或接口获取 access token,然后传入:
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:8787 \
|
||
AUTH_TOKEN='<access-token>' \
|
||
SCENARIO=smoke \
|
||
DETAIL_RATIO=0 \
|
||
npm run loadtest:k6:works
|
||
```
|
||
|
||
不要把 token 写入仓库文件、README 或 shell history 中可共享的位置。
|
||
|
||
## 详情接口压测
|
||
|
||
仅当目标环境存在 `WORKS_DATA` 中的同一批 `profileId/ownerUserId` 时启用:
|
||
|
||
```bash
|
||
BASE_URL=http://127.0.0.1:8787 \
|
||
WORKS_DATA=scripts/loadtest/data/works-list.local.json \
|
||
SCENARIO=smoke \
|
||
DETAIL_RATIO=0.35 \
|
||
npm run loadtest:k6:works
|
||
```
|
||
|
||
如果详情请求返回 404,说明压测数据 ID 未导入目标环境或目标服务数据不一致,应先修正数据源,不要把 404 当成功。
|
||
|
||
## 排障
|
||
|
||
- 如果公开 gallery 返回 `creation_entry_disabled` 或 503,检查本地 creation entry 配置是否禁用了对应入口。
|
||
- 如果个人作品列表返回 401,确认 `AUTH_TOKEN` 是当前 api-server 可识别的 access token。
|
||
- 如果详情全部 404,确认是否已向目标环境导入与 `WORKS_DATA` 一致的数据。
|
||
|
||
## 验证命令
|
||
|
||
```bash
|
||
npx vitest run scripts/loadtest/extract-works-list-data.test.ts
|
||
npx eslint scripts/loadtest/extract-works-list-data.mjs scripts/loadtest/extract-works-list-data.test.ts scripts/loadtest/k6-works-list.js
|
||
```
|