feat:修改压缩工具的配置

This commit is contained in:
zerosaturation 2026-06-16 22:48:32 +08:00
parent 792c891158
commit c6ce7d2d25
11 changed files with 150 additions and 122 deletions

View File

@ -1,7 +1,7 @@
# TopFans Backend Makefile
# 用于简化开发流程
.PHONY: help install-swagger gen-swagger update-swagger start-swagger start-all stop-all clean build run all loadgen-build loadgen-test loadgen-vet loadgen-ci loadgen-seed-local loadgen-seed-prod-tunnel loadgen-cleanup-local loadgen-cleanup-prod-tunnel
.PHONY: help install-swagger gen-swagger update-swagger start-swagger start-all stop-all clean build run all loadgen-build loadgen-test loadgen-vet loadgen-ci loadgen-seed-local loadgen-seed-prod-tunnel loadgen-cleanup-local loadgen-cleanup-prod-tunnel loadgen-cleanup-prod-tunnel-full loadgen-report
# 默认目标
help:
@ -31,8 +31,9 @@ help:
@echo "压测 seed 便捷入口 (免去手敲 flag):"
@echo " make loadgen-seed-local - seed 写入本地 docker dev (top-fans:15432)"
@echo " make loadgen-seed-prod-tunnel - seed 通过 SSH 端口转发写生产 (127.0.0.1:25432)"
@echo " make loadgen-cleanup-local - 清理本地 docker 压测数据"
@echo " make loadgen-cleanup-prod-tunnel - 清理生产 docker 压测数据 (走 SSH 转发)"
@echo " make loadgen-cleanup-local - 清理本地 docker 压测数据 (保留账号)"
@echo " make loadgen-cleanup-prod-tunnel - 清理生产 docker 压测数据 (保留账号,走 SSH 转发)"
@echo " make loadgen-cleanup-prod-tunnel-full - 全清生产压测数据 (含 users + stars,适合彻底收尾)"
@echo ""
@echo "清理:"
@echo " make clean - 清理生成的文件"
@ -56,8 +57,9 @@ help:
@echo "压测 seed 便捷入口 (免去手敲 flag):"
@echo " make loadgen-seed-local - seed 写入本地 docker dev (top-fans:15432)"
@echo " make loadgen-seed-prod-tunnel - seed 通过 SSH 端口转发写生产 (127.0.0.1:25432)"
@echo " make loadgen-cleanup-local - 清理本地 docker 压测数据"
@echo " make loadgen-cleanup-prod-tunnel - 清理生产 docker 压测数据 (走 SSH 转发)"
@echo " make loadgen-cleanup-local - 清理本地 docker 压测数据 (保留账号)"
@echo " make loadgen-cleanup-prod-tunnel - 清理生产 docker 压测数据 (保留账号,走 SSH 转发)"
@echo " make loadgen-cleanup-prod-tunnel-full - 全清生产压测数据 (含 users + stars,适合彻底收尾)"
@echo ""
@echo "清理:"
@echo " make clean - 清理生成的文件"
@ -179,7 +181,7 @@ loadgen-seed-prod-tunnel: loadgen-build
--db-host=127.0.0.1 --db-port=25432 --db-name=topfans --db-user=postgres
loadgen-cleanup-prod-tunnel: loadgen-build
@echo ">>> 清理生产 docker 压测数据 (走 SSH 隧道)"
@echo ">>> 清理生产 docker 压测数据 (走 SSH 隧道, 保留账号)"
@if ! lsof -iTCP:25432 -sTCP:LISTEN >/dev/null 2>&1; then \
echo "❌ 25432 端口未监听,请先: ssh -L 25432:127.0.0.1:5432 -N -f root@101.132.250.62"; \
exit 1; \
@ -188,6 +190,25 @@ loadgen-cleanup-prod-tunnel: loadgen-build
./bin/seed --cleanup \
--db-host=127.0.0.1 --db-port=25432 --db-name=topfans --db-user=postgres
# 全清:连同 users + stars 都删。适合"压测彻底收尾"场景,不是"多轮压测保留账号"。
# 跟 loadgen-cleanup-prod-tunnel 的区别仅在末尾的 --full。
loadgen-cleanup-prod-tunnel-full: loadgen-build
@echo ">>> ⚠️ 全清生产 docker 压测数据 (含 users + stars,走 SSH 隧道)"
@if ! lsof -iTCP:25432 -sTCP:LISTEN >/dev/null 2>&1; then \
echo "❌ 25432 端口未监听,请先: ssh -L 25432:127.0.0.1:5432 -N -f root@101.132.250.62"; \
exit 1; \
fi
@DB_PASSWORD=$$(grep '^DB_PASSWORD=' ../docker/.env.prod | cut -d= -f2) \
./bin/seed --cleanup --full \
--db-host=127.0.0.1 --db-port=25432 --db-name=topfans --db-user=postgres
# 把 reports/ 下的 S*.json + run-metadata.json 合成 final-report.md
loadgen-report: loadgen-build
@echo ">>> 生成 final-report.md"
@./bin/loadgen --cmd=report --input=./reports --output=./reports/final-report.md
@echo "✅ final-report.md 已更新"
@ls -la reports/final-report.md
# 全部:安装依赖 + 生成文档 + 构建
all: install-swagger gen-swagger build
@echo ""

View File

@ -1,12 +1,12 @@
{
"scenario": "S1",
"total_requests": 1072,
"total_requests": 1073,
"errors": 0,
"five_xx": 0,
"p50_us": 173823,
"p95_us": 182015,
"p99_us": 210175,
"max_us": 223999,
"p50_us": 174463,
"p95_us": 182527,
"p99_us": 207615,
"max_us": 318463,
"stages": [
{
"stage_idx": 1,
@ -14,21 +14,21 @@
"total_requests": 300,
"errors": 0,
"five_xx": 0,
"p50_us": 112063,
"p95_us": 122815,
"p99_us": 138751,
"max_us": 214527
"p50_us": 142079,
"p95_us": 151039,
"p99_us": 174719,
"max_us": 242431
},
{
"stage_idx": 2,
"target_rps": 10,
"total_requests": 387,
"total_requests": 388,
"errors": 0,
"five_xx": 0,
"p50_us": 174335,
"p95_us": 182015,
"p99_us": 203519,
"max_us": 259199
"p50_us": 174591,
"p95_us": 182271,
"p99_us": 211583,
"max_us": 336639
},
{
"stage_idx": 3,
@ -36,10 +36,10 @@
"total_requests": 385,
"errors": 0,
"five_xx": 0,
"p50_us": 173823,
"p95_us": 182015,
"p99_us": 210175,
"max_us": 223999
"p50_us": 174463,
"p95_us": 182527,
"p99_us": 207615,
"max_us": 318463
}
]
}

View File

@ -1,45 +1,45 @@
{
"scenario": "S2",
"total_requests": 18,
"total_requests": 2097,
"errors": 0,
"five_xx": 0,
"p50_us": 10487,
"p95_us": 13527,
"p99_us": 13527,
"max_us": 13527,
"p50_us": 24063,
"p95_us": 30799,
"p99_us": 37919,
"max_us": 154367,
"stages": [
{
"stage_idx": 1,
"target_rps": 1,
"total_requests": 3,
"target_rps": 5,
"total_requests": 300,
"errors": 0,
"five_xx": 0,
"p50_us": 13751,
"p95_us": 30815,
"p99_us": 30815,
"max_us": 30815
"p50_us": 24495,
"p95_us": 32367,
"p99_us": 36639,
"max_us": 152447
},
{
"stage_idx": 2,
"target_rps": 2,
"total_requests": 6,
"target_rps": 10,
"total_requests": 600,
"errors": 0,
"five_xx": 0,
"p50_us": 9463,
"p95_us": 11999,
"p99_us": 11999,
"max_us": 11999
"p50_us": 23967,
"p95_us": 30735,
"p99_us": 43391,
"max_us": 147327
},
{
"stage_idx": 3,
"target_rps": 3,
"total_requests": 9,
"target_rps": 20,
"total_requests": 1197,
"errors": 0,
"five_xx": 0,
"p50_us": 10487,
"p95_us": 13527,
"p99_us": 13527,
"max_us": 13527
"p50_us": 24063,
"p95_us": 30799,
"p99_us": 37919,
"max_us": 154367
}
]
}

View File

@ -1,45 +1,45 @@
{
"scenario": "S4",
"total_requests": 18,
"total_requests": 2098,
"errors": 0,
"five_xx": 0,
"p50_us": 6803,
"p95_us": 14167,
"p99_us": 14167,
"max_us": 14167,
"p50_us": 19471,
"p95_us": 23487,
"p99_us": 28335,
"max_us": 142079,
"stages": [
{
"stage_idx": 1,
"target_rps": 1,
"total_requests": 3,
"target_rps": 5,
"total_requests": 300,
"errors": 0,
"five_xx": 0,
"p50_us": 11647,
"p95_us": 15183,
"p99_us": 15183,
"max_us": 15183
"p50_us": 19119,
"p95_us": 25119,
"p99_us": 32447,
"max_us": 45823
},
{
"stage_idx": 2,
"target_rps": 2,
"total_requests": 6,
"target_rps": 10,
"total_requests": 600,
"errors": 0,
"five_xx": 0,
"p50_us": 6651,
"p95_us": 12479,
"p99_us": 12479,
"max_us": 12479
"p50_us": 19231,
"p95_us": 23903,
"p99_us": 33311,
"max_us": 144511
},
{
"stage_idx": 3,
"target_rps": 3,
"total_requests": 9,
"target_rps": 20,
"total_requests": 1198,
"errors": 0,
"five_xx": 0,
"p50_us": 6803,
"p95_us": 14167,
"p99_us": 14167,
"max_us": 14167
"p50_us": 19471,
"p95_us": 23487,
"p99_us": 28335,
"max_us": 142079
}
]
}

View File

@ -1,4 +1,4 @@
scenario,total,errors,five_xx,p50_ms,p95_ms,p99_ms,max_ms,stages
S1,18,0,0,86.14,95.74,95.74,95.74,3
S2,18,0,0,10.48,13.52,13.52,13.52,3
S4,18,0,0,6.80,14.16,14.16,14.16,3
S1,1073,0,0,174.46,182.52,207.61,318.46,3
S2,2097,0,0,24.06,30.79,37.91,154.36,3
S4,2098,0,0,19.47,23.48,28.33,142.07,3

1 scenario total errors five_xx p50_ms p95_ms p99_ms max_ms stages
2 S1 18 1073 0 0 86.14 174.46 95.74 182.52 95.74 207.61 95.74 318.46 3
3 S2 18 2097 0 0 10.48 24.06 13.52 30.79 13.52 37.91 13.52 154.36 3
4 S4 18 2098 0 0 6.80 19.47 14.16 23.48 14.16 28.33 14.16 142.07 3

View File

@ -4,16 +4,17 @@
| 项 | 值 |
|---|---|
| **生成时间** | 2026-06-15 21:06:41 CST |
| **压测开始** | 2026-06-15 21:05:10 CST |
| **压测结束** | 2026-06-15 21:05:38 CST |
| **总耗时** | 27s |
| **目标地址** | `http://localhost:8080` |
| **生成时间** | 2026-06-16 22:30:09 CST |
| **压测开始** | 2026-06-16 22:17:37 CST |
| **压测结束** | 2026-06-16 22:27:00 CST |
| **总耗时** | 9m23s |
| **目标地址** | `http://101.132.250.62:8080` |
| **测试场景** | S1, S2, S4 |
| **阶梯模式** | step (`1,2,3`) |
| **阶梯模式** | step (`5,10,20`) |
| **JWT 签名密钥** | `topfans-***` (前 8 位) |
| **监控模式** | off |
| **总请求数** | 54 |
| **prod SSH** | `root@101.132.250.62` |
| **监控模式** | full |
| **总请求数** | 5,268 |
| **总错误数** | 0 (0.00%) |
| **5xx 数** | 0 (0.00%) |
@ -27,9 +28,9 @@
**场景速览**:
- ✅ **S1 用户登录** — p99=96ms, err 0.00%
- ✅ **S2 浏览资产详情** — p99=14ms, err 0.00%
- ✅ **S4 资产铸造 (mint)** — p99=14ms, err 0.00%
- ✅ **S1 用户登录** — p99=208ms, err 0.00%
- ✅ **S2 浏览资产详情** — p99=38ms, err 0.00%
- ✅ **S4 资产铸造 (mint)** — p99=28ms, err 0.00%
---
@ -37,9 +38,9 @@
| 场景 | 描述 | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms | 拐点 RPS | 状态 |
|------|------|-------|-----|-----|-------|-------|-------|-------|---------|------|
| **S1** | 用户登录 | 18 | 0 (0.00%) | 0 (0.00%) | 86 | 96 | 96 | 96 | — | ✅ |
| **S2** | 浏览资产详情 | 18 | 0 (0.00%) | 0 (0.00%) | 10 | 14 | 14 | 14 | — | ✅ |
| **S4** | 资产铸造 (mint) | 18 | 0 (0.00%) | 0 (0.00%) | 7 | 14 | 14 | 14 | — | ✅ |
| **S1** | 用户登录 | 1,073 | 0 (0.00%) | 0 (0.00%) | 174 | 183 | 208 | 318 | — | ✅ |
| **S2** | 浏览资产详情 | 2,097 | 0 (0.00%) | 0 (0.00%) | 24 | 31 | 38 | 154 | — | ✅ |
| **S4** | 资产铸造 (mint) | 2,098 | 0 (0.00%) | 0 (0.00%) | 19 | 23 | 28 | 142 | — | ✅ |
> 说明: Err 包含 4xx + 5xx,5xx 是子集。错误率 = Err / Total。
@ -49,9 +50,9 @@
**P99 / 阈值 比率** (从高到低):
- S1: 0.10x (96ms)
- S2: 0.03x (14ms)
- S4: 0.01x (14ms)
- S1: 0.21x (208ms)
- S2: 0.08x (38ms)
- S4: 0.01x (28ms)
---
@ -70,24 +71,24 @@
| 指标 | 实测 | 阈值 | 判定 |
|------|------|------|------|
| P50ms | 86 | ≤100 | ✅ |
| P95ms | 96 | ≤300 | ✅ |
| P99ms | 96 | ≤1000 | ✅ |
| Maxms | 96 | — | 参考 |
| P50ms | 174 | ≤100 | 🚨 |
| P95ms | 183 | ≤300 | ✅ |
| P99ms | 208 | ≤1000 | ✅ |
| Maxms | 318 | — | 参考 |
| 错误率 | 0.00% | ≤1.00% | ✅ |
| 5xx 率 | 0.00% | ≤0.10% | ✅ |
### 📍 拐点分析
**拐点未触发** — 全程 3 个 stage 健康运行,最高 3 RPS p99=96ms。
**拐点未触发** — 全程 3 个 stage 健康运行,最高 20 RPS p99=208ms。
### 🔢 阶梯结果
| Stage | TargetRPS | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms | 涨幅 |
|-------|-----------|-------|-----|-----|-------|-------|-------|-------|------|
| 1 | 1 | 3 | 0 | 0 | 94 | 98 | 98 | 98 | |
| 2 | 2 | 6 | 0 | 0 | 87 | 89 | 89 | 89 | -9% |
| 3 | 3 | 9 | 0 | 0 | 86 | 96 | 96 | 96 | +7% |
| 1 | 5 | 300 | 0 | 0 | 142 | 151 | 175 | 242 | |
| 2 | 10 | 388 | 0 | 0 | 175 | 182 | 212 | 337 | +21% |
| 3 | 20 | 385 | 0 | 0 | 174 | 183 | 208 | 318 | -2% |
### 🎯 行动项
@ -114,24 +115,24 @@
| 指标 | 实测 | 阈值 | 判定 |
|------|------|------|------|
| P50ms | 10 | ≤50 | ✅ |
| P95ms | 14 | ≤150 | ✅ |
| P99ms | 14 | ≤500 | ✅ |
| Maxms | 14 | — | 参考 |
| P50ms | 24 | ≤50 | ✅ |
| P95ms | 31 | ≤150 | ✅ |
| P99ms | 38 | ≤500 | ✅ |
| Maxms | 154 | — | 参考 |
| 错误率 | 0.00% | ≤1.00% | ✅ |
| 5xx 率 | 0.00% | ≤0.10% | ✅ |
### 📍 拐点分析
**拐点未触发** — 全程 3 个 stage 健康运行,最高 3 RPS p99=14ms。
**拐点未触发** — 全程 3 个 stage 健康运行,最高 20 RPS p99=38ms。
### 🔢 阶梯结果
| Stage | TargetRPS | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms | 涨幅 |
|-------|-----------|-------|-----|-----|-------|-------|-------|-------|------|
| 1 | 1 | 3 | 0 | 0 | 14 | 31 | 31 | 31 | |
| 2 | 2 | 6 | 0 | 0 | 9 | 12 | 12 | 12 | -61% |
| 3 | 3 | 9 | 0 | 0 | 10 | 14 | 14 | 14 | +13% |
| 1 | 5 | 300 | 0 | 0 | 24 | 32 | 37 | 152 | |
| 2 | 10 | 600 | 0 | 0 | 24 | 31 | 43 | 147 | +18% |
| 3 | 20 | 1,197 | 0 | 0 | 24 | 31 | 38 | 154 | -13% |
### 🎯 行动项
@ -158,24 +159,24 @@
| 指标 | 实测 | 阈值 | 判定 |
|------|------|------|------|
| P50ms | 7 | ≤300 | ✅ |
| P95ms | 14 | ≤800 | ✅ |
| P99ms | 14 | ≤2000 | ✅ |
| Maxms | 14 | — | 参考 |
| P50ms | 19 | ≤300 | ✅ |
| P95ms | 23 | ≤800 | ✅ |
| P99ms | 28 | ≤2000 | ✅ |
| Maxms | 142 | — | 参考 |
| 错误率 | 0.00% | ≤1.00% | ✅ |
| 5xx 率 | 0.00% | ≤0.10% | ✅ |
### 📍 拐点分析
**拐点未触发** — 全程 3 个 stage 健康运行,最高 3 RPS p99=14ms。
**拐点未触发** — 全程 3 个 stage 健康运行,最高 20 RPS p99=28ms。
### 🔢 阶梯结果
| Stage | TargetRPS | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms | 涨幅 |
|-------|-----------|-------|-----|-----|-------|-------|-------|-------|------|
| 1 | 1 | 3 | 0 | 0 | 12 | 15 | 15 | 15 | |
| 2 | 2 | 6 | 0 | 0 | 7 | 12 | 12 | 12 | -18% |
| 3 | 3 | 9 | 0 | 0 | 7 | 14 | 14 | 14 | +14% |
| 1 | 5 | 300 | 0 | 0 | 19 | 25 | 32 | 46 | |
| 2 | 10 | 600 | 0 | 0 | 19 | 24 | 33 | 145 | +3% |
| 3 | 20 | 1,198 | 0 | 0 | 19 | 23 | 28 | 142 | -15% |
### 🎯 行动项
@ -222,7 +223,8 @@ reports/
```bash
cd /opt/topfans/loadtest
./loadgen --cmd=run --scenarios=S1,S2,S4 --stage=step --step-schedule='1,2,3' \
--target=http://localhost:8080 \
--monitor=off \
./loadgen --cmd=run --scenarios=S1,S2,S4 --stage=step --step-schedule='5,10,20' \
--target=http://101.132.250.62:8080 \
--monitor=full \
--prod-ssh=root@101.132.250.62
```

View File

@ -1,6 +1,6 @@
{
"start_time": "2026-06-16T22:10:55.266986+08:00",
"end_time": "2026-06-16T22:13:55.674244+08:00",
"start_time": "2026-06-16T22:17:37.426542+08:00",
"end_time": "2026-06-16T22:27:00.295966+08:00",
"target": "http://101.132.250.62:8080",
"scenarios": [
"S1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -23,15 +23,20 @@ func Cleanup(db *sql.DB, starID int64, full bool) error {
}
if full {
queries = append(queries,
"DELETE FROM users WHERE id BETWEEN $1 AND $2",
// 用 id >= LoadtestUserMin 而非 BETWEEN,避免漏掉压测期间
// 通过 nextval(users_id_seq) 插入的 id > LoadtestUserMax 的边界行
// (如 S4 mint 场景触发 userservice 注册新用户)。
// LoadtestUserMin = 30000001 远大于真实用户 id 范围(< 1000000),
// 不会误删真实用户。
"DELETE FROM users WHERE id >= $1",
"DELETE FROM stars WHERE star_id = $1",
)
}
for _, q := range queries {
var err error
switch q {
case "DELETE FROM users WHERE id BETWEEN $1 AND $2":
_, err = db.Exec(q, LoadtestUserMin, LoadtestUserMax)
case "DELETE FROM users WHERE id >= $1":
_, err = db.Exec(q, LoadtestUserMin)
default:
_, err = db.Exec(q, starID)
}