187 lines
7.8 KiB
Markdown
187 lines
7.8 KiB
Markdown
# IM 单机 60% 容量压力测试方案
|
||
|
||
日期:2026-09-29
|
||
|
||
本方案首轮执行结果见 [IM-单机60%容量压力测试结果-20260929.md](./IM-单机60%容量压力测试结果-20260929.md)。
|
||
|
||
## 1. 目标与口径
|
||
|
||
本方案用一台物理压测机完成单聊、群聊和混合场景,容量按双机正式方案全局规模的 60% 计算。
|
||
|
||
单机不等于只运行一个 agent。为保留现有好友对和投递契约,同一台物理机上同时运行逻辑 agent A 和 agent B,每个 agent 承载 600 个连接,合计 1200 个 WebSocket。Coordinator 仍使用 `expected-agents=2`。
|
||
|
||
| 项目 | 双机正式方案 | 单机 60% 方案 |
|
||
|---|---:|---:|
|
||
| 物理压测机 | 2 | 1 |
|
||
| 逻辑 agent | 2 | 2 |
|
||
| 每个 agent 连接 | 1000 | 600 |
|
||
| WebSocket 总连接 | 2000 | 1200 |
|
||
| 好友对 | 1000 | 600 |
|
||
| 群成员 | 2000 | 1200 |
|
||
|
||
## 2. 场景容量
|
||
|
||
### 2.1 单聊
|
||
|
||
- 600 对好友,A/B 各 600 人。
|
||
- 每个用户发送 10 条,每秒 1 条。
|
||
- 总发送尝试 12000 条,是双机 20000 条的 60%。
|
||
- 每条 ACK 消息应在配对用户的 WebSocket 到达一次。
|
||
|
||
### 2.2 群聊
|
||
|
||
- 1200 个在线群成员。
|
||
- A/B 各取前 300 个用户作为发送者,合计 600 个发送者。
|
||
- 每人发送 2 条,全局每 100ms 一条,合计 1200 条群消息,耗时约 120 秒。
|
||
- 全部发送被 ACK 时,期望实时投递 `1200 x 1200 = 1,440,000` 次。
|
||
|
||
### 2.3 单聊和群聊混合
|
||
|
||
- 前 180 对好友互发,每人 5 条,共 1800 条单聊。
|
||
- A/B 各 150 个群发送者,每人 2 条,共 600 条群消息。
|
||
- 群消息期望实时投递 `600 x 1200 = 720,000` 次。
|
||
- 单聊和群聊同时开始,不分两轮单独执行。
|
||
|
||
工具按 `users_per_machine` 等比计算发送者数量。`users_per_machine=1000` 时保持原双机参数,设为 600 时自动使用上述单机参数。
|
||
|
||
## 3. 文件隔离
|
||
|
||
单机方案不复用双机的运行文件,避免把 1200 人结果和 2000 人结果混在一起。
|
||
|
||
```text
|
||
loadtest/im-pressure/config.single-machine.json
|
||
loadtest/im-pressure/manifest.single-machine.json
|
||
loadtest/im-pressure/results/<RUN_ID>/
|
||
```
|
||
|
||
从模板生成本地配置:
|
||
|
||
```bash
|
||
cp loadtest/im-pressure/config.single-machine.example.json \
|
||
loadtest/im-pressure/config.single-machine.json
|
||
chmod 600 loadtest/im-pressure/config.single-machine.json
|
||
```
|
||
|
||
修改租户、HTTP/WS 地址和注册手机前缀。A/B endpoint 可以填同一个公网入口;若需确认跨 Pod 投递,应分别填写两个定向入口。
|
||
|
||
## 4. 一次性数据准备
|
||
|
||
```bash
|
||
source loadtest/im-pressure/.env.test
|
||
go build -o loadtest/im-pressure/im-pressure ./loadtest/im-pressure
|
||
ulimit -n 100000
|
||
|
||
./loadtest/im-pressure/im-pressure prepare \
|
||
-config loadtest/im-pressure/config.single-machine.json \
|
||
-manifest loadtest/im-pressure/manifest.single-machine.json
|
||
|
||
./loadtest/im-pressure/im-pressure verify \
|
||
-config loadtest/im-pressure/config.single-machine.json \
|
||
-manifest loadtest/im-pressure/manifest.single-machine.json
|
||
```
|
||
|
||
`verify` 必须输出 1200 个账号、600 对好友和 1200 个群成员。单机 manifest 可以复用已注册的 `lta0001..0600` 和 `ltb0001..0600` 账号,但必须使用独立群 Topic。
|
||
|
||
## 5. 正式运行
|
||
|
||
以群聊为例:
|
||
|
||
```bash
|
||
export RUN_ID='single60-group-r1-YYYYMMDD-01'
|
||
export SCENARIO='group'
|
||
mkdir -p "loadtest/im-pressure/results/${RUN_ID}"
|
||
```
|
||
|
||
终端 1,启动 coordinator:
|
||
|
||
```bash
|
||
./loadtest/im-pressure/im-pressure coordinator \
|
||
-listen :8090 \
|
||
-run-id "${RUN_ID}" \
|
||
-scenario "${SCENARIO}" \
|
||
-expected-agents 2 \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/coordinator.json"
|
||
```
|
||
|
||
终端 2,启动逻辑 agent A:
|
||
|
||
```bash
|
||
./loadtest/im-pressure/im-pressure agent \
|
||
-config loadtest/im-pressure/config.single-machine.json \
|
||
-manifest loadtest/im-pressure/manifest.single-machine.json \
|
||
-machine a \
|
||
-coordinator http://127.0.0.1:8090 \
|
||
-metrics-listen :9105 \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/agent-a-summary.json"
|
||
```
|
||
|
||
终端 3,启动逻辑 agent B:
|
||
|
||
```bash
|
||
./loadtest/im-pressure/im-pressure agent \
|
||
-config loadtest/im-pressure/config.single-machine.json \
|
||
-manifest loadtest/im-pressure/manifest.single-machine.json \
|
||
-machine b \
|
||
-coordinator http://127.0.0.1:8090 \
|
||
-metrics-listen :9106 \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/agent-b-summary.json"
|
||
```
|
||
|
||
两个 agent 都报告 `600/600 READY` 并稳定通过 30 秒屏障后才会开始。任一 agent 未满连接时 coordinator 会撤销开始时间。
|
||
|
||
## 6. 指标采集
|
||
|
||
终端 4 在起压前至少 2 分钟启动:
|
||
|
||
```bash
|
||
./loadtest/im-pressure/im-pressure collect \
|
||
-duration 20m -interval 5s \
|
||
-coordinator http://127.0.0.1:8090 \
|
||
-coordinator-output "loadtest/im-pressure/results/${RUN_ID}/coordinator.json" \
|
||
-url agent-a=http://127.0.0.1:9105/metrics \
|
||
-url agent-b=http://127.0.0.1:9106/metrics \
|
||
-url node=http://127.0.0.1:9100/metrics \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/metrics.jsonl"
|
||
```
|
||
|
||
同时采集 Redis、Kafka、MySQL、Pod CPU/内存/网络、Kafka consumer lag、MySQL 连接池等指标。如本机没有 `node-exporter :9100`,删除 `node` URL,但不影响 agent 指标采集。
|
||
|
||
发版后必须在服务端 `/metrics` 确认 `im_ws_heartbeat_seconds{setting="ping_period"}=15`、`im_ws_heartbeat_seconds{setting="pong_wait"}=90`,并采集 `im_ws_heartbeat_total{event="pong_received"}` 和 `im_ws_disconnect_total{reason="timeout"}` 的分 Pod 增量。
|
||
|
||
## 7. 报告和独立落库核验
|
||
|
||
```bash
|
||
./loadtest/im-pressure/im-pressure merge \
|
||
-a "loadtest/im-pressure/results/${RUN_ID}/agent-a-summary.json" \
|
||
-b "loadtest/im-pressure/results/${RUN_ID}/agent-b-summary.json" \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/report.json"
|
||
|
||
export MYSQL_DSN='readonly:password@tcp(mysql-host:3306)/meeting_im?parseTime=true'
|
||
export TENANT='006' # 必须与 config.single-machine.json 中的 tenant 一致
|
||
./loadtest/im-pressure/im-pressure verify-db \
|
||
-coordinator "loadtest/im-pressure/results/${RUN_ID}/coordinator.json" \
|
||
-tenant "${TENANT}" \
|
||
-dsn-env MYSQL_DSN \
|
||
-registry-db hotgo \
|
||
-output "loadtest/im-pressure/results/${RUN_ID}/db-verification.json"
|
||
```
|
||
|
||
## 8. 验收门禁
|
||
|
||
- READY 必须是 `1200/1200`,统计窗口内断连为 0。
|
||
- publish 明确拒绝和结果未知均为 0,成功率至少 99.99%。
|
||
- ACK P95 不高于 500ms,同机投递 P95 不高于 1000ms。
|
||
- 实时缺失、重复、乱序、未知本轮消息均为 0。
|
||
- ACK 台账和无 ACK 但已观测台账的历史回查命中率必须 100%,独立 MySQL 核验丢失、错配、重复均为 0。
|
||
- 实时发送、历史回查和渐进关闭三个阶段分别统计 Topic/Proxy/Session 队列满,不能只看整轮总数。
|
||
|
||
## 9. 单机特有风险
|
||
|
||
1. 两个 agent 共用一台机器的 CPU、内存、FD、NAT 和出口带宽,测到的是“单机压测端 + 服务端”综合上限,不能代替双机最终验收。
|
||
2. 正式前做 120/600/1200 连接三档阶梯,观察 agent CPU、`go_goroutines`、FD、接收速率和 Ping/Pong 断连,确认压测端本身没有先饱和。当前工具已将投递观测按 `client_mid` 分片、接收账号顺序状态独立加锁,使用原子延迟直方图,并将数据统计回调从 WebSocket socket 读循环解耦;仍需用指标证明本机有余量。
|
||
3. 两个 agent 必须使用不同指标端口,不能同时绑定 `:9105`。
|
||
4. 压测域名如被 VPN/TUN 接管,起压前必须确认所有当前 IP 的路由都指向物理网卡。
|
||
5. 单机 60% 通过后只能进入双机 100% 验收,不能直接得出 2000 连接容量通过的结论。
|
||
|
||
断连时同时查看 agent summary 中的 `disconnect_reasons` 和 `disconnect_samples`。前者按 timeout、abnormal close、connection reset 等原因分类计数,后者最多保留 100 条带账号与时间的原始错误样本,用于区分压测端读循环阻塞、网络中断和服务端主动关闭。
|