Add stress test tool with crash test mode

- stress_test.py: async HTTP stress tester with aiohttp
- Features: concurrency control, realtime display, find-limit mode, crash-test mode
- crash-test: finds critical, warning, and crash concurrency points
- USAGE.md: detailed usage documentation
- Sample reports and URL list examples
This commit is contained in:
guanjun 2026-06-02 19:36:28 -07:00
parent dfe29fdfa2
commit 20a79b9a23
8 changed files with 1715 additions and 0 deletions

535
USAGE.md Executable file
View File

@ -0,0 +1,535 @@
# Website Stress Testing Tool - 使用说明
基于 Python 异步框架的网站压力测试工具,用于评估网站在高并发下的承载能力。
---
## 目录
1. [环境要求](#1-环境要求)
2. [安装](#2-安装)
3. [快速开始](#3-快速开始)
4. [参数详解](#4-参数详解)
5. [使用场景](#5-使用场景)
6. [输出说明](#6-输出说明)
7. [最佳实践](#7-最佳实践)
8. [常见问题](#8-常见问题)
---
## 1. 环境要求
- Python >= 3.8
- 依赖aiohttp >= 3.9.0
---
## 2. 安装
```bash
# 进入工具目录
cd d:\work\work-KD\tools
# 安装依赖
pip install -r requirements.txt
# 或直接安装
pip install aiohttp
```
验证安装:
```bash
python stress_test.py --help
```
---
## 3. 快速开始
### 最简单的用法
```bash
# 对 example.com 发送 100 个请求,并发数 10
python stress_test.py -u https://example.com -n 100
# 持续压测 30 秒
python stress_test.py -u https://example.com -d 30
```
### 提高并发
```bash
# 100 并发1000 请求
python stress_test.py -u https://example.com -c 100 -n 1000
```
### 查看帮助
```bash
python stress_test.py --help
```
---
## 4. 参数详解
### 4.1 目标参数(必选,二选一)
| 参数 | 说明 | 示例 |
|------|------|------|
| `-u, --url` | 目标 URL可多次指定 | `-u https://a.com -u https://b.com` |
| `-f, --file` | URL 列表文件路径 | `-f urls.txt` |
**URL 文件格式:**
```
# 这是注释行
https://example.com
https://example.com/api
https://example.com/about
```
- 每行一个 URL
- `#` 开头为注释
- 空行自动忽略
- 可省略 `https://` 前缀(自动补全)
### 4.2 测试模式(必选,二选一)
| 参数 | 说明 | 示例 |
|------|------|------|
| `-n, --num-requests` | 总请求数,达到后停止 | `-n 1000` |
| `-d, --duration` | 持续时间(秒),到期后停止 | `-d 60` |
### 4.3 并发控制
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `-c, --concurrency` | 10 | 并发 worker 数量 |
| `-r, --ramp-up` | 0 | 渐进加压时间(秒),从 1 并发逐步增加到目标并发 |
**渐进加压示例:**
```bash
# 100 并发,但用 30 秒逐步加压(避免瞬间打垮服务器)
python stress_test.py -u https://example.com -c 100 -d 120 -r 30
```
### 4.4 HTTP 请求配置
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `-m, --method` | GET | HTTP 方法GET / POST / PUT / DELETE / PATCH / HEAD |
| `-H, --header` | 无 | 自定义请求头,格式:`-H "Key: Value"`,可多次使用 |
| `--cookie` | 无 | Cookie格式`k1=v1;k2=v2` |
| `--data` | 无 | 请求体(字符串) |
| `--json` | 无 | 请求体JSON 格式) |
### 4.5 网络参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `-t, --timeout` | 30 | 单次请求超时时间(秒) |
| `--no-verify-ssl` | false | 跳过 SSL 证书验证 |
| `--no-keep-alive` | false | 禁用 HTTP Keep-Alive |
### 4.6 输出控制
| 参数 | 说明 |
|------|------|
| `--report FILE` | 将 JSON 格式报告保存到指定文件 |
| `--no-display` | 禁用实时统计面板(适合日志采集或 CI 环境) |
---
## 5. 使用场景
### 场景一:基础网站可用性测试
```bash
python stress_test.py -u https://your-site.com -c 50 -n 500
```
评估网站在 50 并发下的基本响应能力。
### 场景二API 接口压力测试
```bash
python stress_test.py \
-u https://api.example.com/v1/users \
-m GET \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-c 100 \
-n 2000
```
测试需要认证的 API 接口。
### 场景三POST 提交测试
```bash
python stress_test.py \
-u https://api.example.com/login \
-m POST \
-H "Content-Type: application/json" \
--data '{"username":"testuser","password":"testpass"}' \
-c 50 \
-n 500
```
### 场景四:表单提交测试
```bash
python stress_test.py \
-u https://example.com/contact \
-m POST \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "name=test&email=test@example.com&message=hello" \
-c 30 \
-n 300
```
### 场景五:多页面轮询测试
```bash
# 从文件加载多个 URL模拟真实用户访问不同页面
python stress_test.py -f urls.txt -c 50 -d 120
```
`urls.txt` 内容:
```
https://example.com/
https://example.com/products
https://example.com/about
https://example.com/contact
https://example.com/api/search?q=test
```
### 场景六:渐进加压测试
```bash
# 用 60 秒从 0 加压到 200 并发,持续测试 5 分钟
python stress_test.py -u https://example.com -c 200 -d 300 -r 60
```
逐步增加负载,观察系统在哪一级开始出现问题。
### 场景七:带 Cookie 的登录态测试
```bash
python stress_test.py \
-u https://example.com/dashboard \
--cookie "session_id=abc123;user_id=42" \
-c 50 \
-d 60
```
### 场景八:跳过 SSL 验证(自签名证书)
```bash
python stress_test.py -u https://internal.dev.local -c 20 -n 100 --no-verify-ssl
```
### 场景九CI/CD 自动化测试
```bash
# 静默模式 + JSON 报告,适合集成到自动化流程
python stress_test.py \
-u https://staging.example.com \
-c 50 \
-n 1000 \
--no-display \
--report stress_result.json
```
### 场景十:多站点对比测试
```bash
# 同时测试多个站点(轮询模式)
python stress_test.py \
-u https://server-a.example.com \
-u https://server-b.example.com \
-c 50 \
-n 500
```
---
## 6. 输出说明
### 6.1 实时统计面板
测试运行时,终端每 0.5 秒刷新一次:
```
============================================================
| Stress Test Running
------------------------------------------------------------
进度: [###############...................] 50.0% (500/1000)
QPS: 152.3 req/s
并发数: 100
总请求: 500
耗时: 0:00:03
平均延迟: 45.2 ms
P50: 38.1 ms
P90: 72.5 ms
P99: 156.3 ms
成功率: 99.80% (成功: 499 失败: 1)
吞吐量: 1.2 MB/s
============================================================
```
| 指标 | 说明 |
|------|------|
| QPS | 每秒完成的请求数 |
| P50 | 50% 的请求在此延迟内完成(中位数) |
| P90 | 90% 的请求在此延迟内完成 |
| P99 | 99% 的请求在此延迟内完成 |
| 成功率 | HTTP 2xx/3xx 响应占比 |
### 6.2 最终报告
测试完成后自动输出完整报告:
```
================================================================
[*] 压力测试报告
2026-05-28 15:40:13
================================================================
> 测试配置
目标 URL: https://example.com
HTTP 方法: GET
并发数: 100
总耗时: 6.52s
> 请求统计
总请求数: 1000
成功: 998
失败: 2
成功率: 99.80%
平均 QPS: 153.4 req/s
> 延迟分布 (ms)
P50 38.1 ms ##......................
P75 55.2 ms ####..................
P90 72.5 ms #####.................
P95 102.8 ms ########..............
P99 156.3 ms ############..........
P99.9 312.1 ms ####################..
最小: 12.3 ms
最大: 312.1 ms
平均: 45.2 ms
标准差: 28.7 ms
> 吞吐量
总传输: 2.4 MB
吞吐量: 378.5 KB/s
> 状态码分布
HTTP 200 998 ####################
HTTP 502 2 #...................
> 综合评价
[Good] 良好 - 网站表现正常
================================================================
```
### 6.3 JSON 报告(--report
```json
{
"timestamp": "2026-05-28T15:40:13.123456",
"config": {
"urls": ["https://example.com"],
"method": "GET",
"concurrency": 100,
"total_requests": 1000,
"duration": null
},
"results": {
"total_requests": 1000,
"success": 998,
"errors": 2,
"success_rate": 99.8,
"elapsed_seconds": 6.52,
"avg_qps": 153.4,
"avg_latency_ms": 45.23,
"p50_ms": 38.1,
"p90_ms": 72.5,
"p95_ms": 102.8,
"p99_ms": 156.3,
"total_bytes": 2516480,
"throughput_bytes_sec": 386729.1,
"status_codes": {
"200": 998,
"502": 2
},
"errors_detail": {
"Timeout": 1,
"ClientConnectorError": 1
}
}
}
```
可用于:
- 存档记录
- 自动化流水线中的质量门禁
- 与 Grafana/Prometheus 等监控系统集成
- Python/JS 脚本二次分析
### 6.4 综合评价标准
| 等级 | 条件 | 含义 |
|------|------|------|
| Excellent | 成功率 >= 99.9% 且 P99 < 500ms | 优秀可放心上线 |
| Good | 成功率 >= 99% 且 P99 < 1000ms | 良好表现正常 |
| Fair | 成功率 >= 95% | 一般,建议优化 |
| Poor | 成功率 >= 80% | 较差,需要关注 |
| Bad | 成功率 < 80% | 很差无法承受负载 |
---
## 7. 最终实践
### 7.1 测试前准备
1. **确认权限** - 只对你拥有或获得授权的网站进行压测
2. **选择低峰期** - 避免影响正常用户
3. **从小到大** - 先用小并发验证脚本正确,再逐步加压
4. **通知相关方** - 提前告知运维/开发团队
### 7.2 推荐测试流程
```
第 1 轮:验证脚本
python stress_test.py -u http://118.89.55.254 -c 5 -n 20
第 2 轮:基准测试
python stress_test.py -u http://118.89.55.254 -c 10 -n 100
第 3 轮:负载测试
python stress_test.py -u http://118.89.55.254 -c 50 -n 1000
第 4 轮:压力测试
python stress_test.py -u http://118.89.55.254 -c 100 -d 300 -r 30
第 5 轮:极限测试
python stress_test.py -u http://118.89.55.254 -c 500 -d 300 -r 60
```
### 7.3 并发数建议
| 场景 | 建议并发数 | 说明 |
|------|-----------|------|
| 个人博客/小型站点 | 10 - 50 | 通常单机部署 |
| 企业官网 | 50 - 200 | 可能有 CDN |
| 中型 API 服务 | 100 - 500 | 取决于后端架构 |
| 大型平台 | 500 - 2000 | 建议使用分布式工具 |
> 注意:单机压测受限于本机 CPU/内存/带宽,并发数过高时瓶颈可能在测试端而非目标服务器。
### 7.4 如何解读结果
- **QPS 随并发增加而趋于平稳** -> 系统已达到瓶颈
- **P99 延迟突增** -> 存在长尾请求,可能有慢查询或资源竞争
- **成功率下降** -> 服务器开始拒绝请求或超时
- **HTTP 502/503 增多** -> 后端服务过载或网关超时
- **Timeout 增多** -> 服务器处理不过来,请求排队
---
## 8. 常见问题
### Q: 提示 "需要安装 aiohttp"
```bash
pip install aiohttp
```
### Q: 中文显示乱码
Windows 默认终端使用 GBK 编码。解决方法:
```bash
# 方法 1使用 Windows Terminal推荐
# 方法 2切换终端编码
chcp 65001
# 方法 3使用 --no-display 导出 JSON 报告
python stress_test.py -u https://site.com -n 100 --no-display --report result.json
```
### Q: 出现 "Event loop is closed" 警告
这是 Python 3.8 在 Windows 上的已知无害警告,不影响测试结果。升级到 Python 3.9+ 可消除。
### Q: 测试端成为瓶颈怎么办
- 减少并发数
- 在多台机器上分别运行(各自测试不同 URL 子集)
- 使用更专业的分布式工具(如 Locust、k6
### Q: 如何测试 WebSocket
当前版本仅支持 HTTP/HTTPS。如需 WebSocket 测试,建议使用专业工具。
### Q: 如何测试需要登录的页面
```bash
# 方法 1通过 Cookie
python stress_test.py -u https://site.com/dashboard \
--cookie "session=abc123" -c 20 -n 100
# 方法 2通过 HeaderToken 认证)
python stress_test.py -u https://api.site.com/data \
-H "Authorization: Bearer eyJhbG..." -c 20 -n 100
```
### Q: 支持 HTTP/2 吗
当前使用 aiohttp默认 HTTP/1.1。如需 HTTP/2 支持,可考虑替换为 httpx。
---
## 完整参数速查表
```
用法: python stress_test.py [目标] [模式] [选项]
目标(必选,二选一):
-u URL 目标 URL可多次指定
-f FILE URL 列表文件
模式(必选,二选一):
-n NUM 总请求数
-d SECONDS 持续时间(秒)
并发:
-c NUM 并发数(默认: 10
-r SECONDS 渐进加压时间(默认: 0
HTTP:
-m METHOD GET/POST/PUT/DELETE/PATCH/HEAD默认: GET
-H "K: V" 自定义请求头(可多次使用)
--cookie "K=V" Cookie
--data STRING 请求体(字符串)
--json '{}' 请求体JSON
网络:
-t SECONDS 超时时间(默认: 30
--no-verify-ssl 跳过 SSL 验证
--no-keep-alive 禁用 Keep-Alive
输出:
--report FILE 保存 JSON 报告
--no-display 禁用实时显示
```

34
r100.json Executable file
View File

@ -0,0 +1,34 @@
{
"timestamp": "2026-05-29T08:52:03.256740",
"config": {
"urls": [
"http://118.89.55.254"
],
"method": "GET",
"concurrency": 100,
"total_requests": null,
"duration": 30
},
"results": {
"total_requests": 2732,
"success": 2721,
"errors": 11,
"success_rate": 99.6,
"elapsed_seconds": 38.23,
"avg_qps": 71.5,
"avg_latency_ms": 1132.38,
"p50_ms": 433.26,
"p90_ms": 2242.57,
"p95_ms": 4382.01,
"p99_ms": 13778.92,
"total_bytes": 38417799,
"throughput_bytes_sec": 1004842.8,
"status_codes": {
"200": 2721,
"0": 11
},
"errors_detail": {
"Timeout": 11
}
}
}

34
r200.json Executable file
View File

@ -0,0 +1,34 @@
{
"timestamp": "2026-05-29T08:53:19.265742",
"config": {
"urls": [
"http://118.89.55.254"
],
"method": "GET",
"concurrency": 200,
"total_requests": null,
"duration": 30
},
"results": {
"total_requests": 2998,
"success": 2902,
"errors": 96,
"success_rate": 96.8,
"elapsed_seconds": 45.14,
"avg_qps": 66.4,
"avg_latency_ms": 2058.16,
"p50_ms": 562.24,
"p90_ms": 2626.2,
"p95_ms": 8781.4,
"p99_ms": 30109.4,
"total_bytes": 40973338,
"throughput_bytes_sec": 907561.0,
"status_codes": {
"200": 2902,
"0": 96
},
"errors_detail": {
"Timeout": 96
}
}
}

34
r500.json Executable file
View File

@ -0,0 +1,34 @@
{
"timestamp": "2026-05-29T08:55:03.464684",
"config": {
"urls": [
"http://118.89.55.254"
],
"method": "GET",
"concurrency": 500,
"total_requests": null,
"duration": 30
},
"results": {
"total_requests": 3127,
"success": 2833,
"errors": 294,
"success_rate": 90.6,
"elapsed_seconds": 50.54,
"avg_qps": 61.9,
"avg_latency_ms": 5131.72,
"p50_ms": 1099.29,
"p90_ms": 27384.13,
"p95_ms": 30285.08,
"p99_ms": 30483.01,
"total_bytes": 39999127,
"throughput_bytes_sec": 791378.9,
"status_codes": {
"200": 2833,
"0": 294
},
"errors_detail": {
"Timeout": 294
}
}
}

1
requirements.txt Executable file
View File

@ -0,0 +1 @@
aiohttp>=3.9.0

1040
stress_test.py Executable file

File diff suppressed because it is too large Load Diff

31
test_result.json Executable file
View File

@ -0,0 +1,31 @@
{
"timestamp": "2026-05-29T08:21:25.325564",
"config": {
"urls": [
"http://118.89.55.254"
],
"method": "GET",
"concurrency": 20,
"total_requests": 100,
"duration": null
},
"results": {
"total_requests": 124,
"success": 124,
"errors": 0,
"success_rate": 100.0,
"elapsed_seconds": 1.39,
"avg_qps": 88.9,
"avg_latency_ms": 167.43,
"p50_ms": 75.7,
"p90_ms": 375.06,
"p95_ms": 1055.75,
"p99_ms": 1100.21,
"total_bytes": 1750756,
"throughput_bytes_sec": 1255476.5,
"status_codes": {
"200": 124
},
"errors_detail": {}
}
}

6
urls_example.txt Executable file
View File

@ -0,0 +1,6 @@
# 示例 URL 列表文件
# 每行一个 URL# 开头的行为注释
https://example.com
https://example.com/api
https://example.com/about