Files
hfb_sys/docs/stress-test-guide.md
T
2026-06-05 22:01:14 +08:00

607 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 压力测试指南
本文档提供完整的压力测试方案,用于评估系统在大数据量和高并发场景下的性能表现。
## 一、测试环境准备
### 1.1 硬件配置建议
**最低配置:**
- CPU: 4核
- 内存: 8GB
- 磁盘: SSD 50GB
**推荐配置:**
- CPU: 8核+
- 内存: 16GB+
- 磁盘: SSD 100GB+
- MySQL: 独立部署,开启慢查询日志
### 1.2 数据库优化配置
`deploy/docker-compose.dev.yml` 中调整 MySQL 配置:
```yaml
services:
mysql:
environment:
- MYSQL_ROOT_PASSWORD=secret
command:
- --max_connections=500
- --innodb_buffer_pool_size=2G
- --innodb_log_file_size=512M
- --slow_query_log=1
- --slow_query_log_file=/var/log/mysql/slow.log
- --long_query_time=0.5
```
### 1.3 后端配置优化
`backend/.env` 中调整:
```bash
# 数据库连接池
DB_MAX_OPEN_CONNS=100
DB_MAX_IDLE_CONNS=20
DB_CONN_MAX_LIFETIME=3600
# Redis配置
REDIS_POOL_SIZE=50
# 日志级别(压测时降低日志输出)
LOG_LEVEL=warn
# Gin模式
APP_ENV=production
```
## 二、生成测试数据
### 2.1 执行数据生成脚本
```bash
# 连接到数据库容器
docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < scripts/load_test_data.sql
```
### 2.2 数据规模说明
该脚本会生成:
- **10,000** 个用户(90%已实名)
- **50,000** 个租号商品
- **30,000** 个订单(包含各种状态)
- **100,000** 条钱包流水
- **50,000** 条聊天消息
### 2.3 验证数据生成
```sql
-- 查看数据统计
SELECT '用户数' as item, COUNT(*) as count FROM users
UNION ALL
SELECT '商品数', COUNT(*) FROM rental_listings
UNION ALL
SELECT '订单数', COUNT(*) FROM rental_orders
UNION ALL
SELECT '钱包流水', COUNT(*) FROM wallet_ledger;
```
### 2.4 自定义数据量
修改脚本底部的调用参数:
```sql
-- 根据需要调整数量
CALL generate_users(50000); -- 生成5万用户
CALL generate_listings(200000); -- 生成20万商品
CALL generate_orders(100000); -- 生成10万订单
CALL generate_wallet_ledger(500000); -- 生成50万流水
```
## 三、索引优化验证
### 3.1 检查现有索引
```sql
-- 查看订单表索引
SHOW INDEX FROM rental_orders;
-- 查看钱包流水索引
SHOW INDEX FROM wallet_ledger;
-- 查看商品表索引
SHOW INDEX FROM rental_listings;
```
### 3.2 分析慢查询
```sql
-- 分析商品列表查询
EXPLAIN SELECT * FROM rental_listings
WHERE status = 'active'
AND review_status = 'approved'
ORDER BY published_at DESC
LIMIT 20;
-- 分析用户订单查询
EXPLAIN SELECT * FROM rental_orders
WHERE renter_id = 1234
AND status = 'active'
ORDER BY created_at DESC;
-- 分析钱包流水查询
EXPLAIN SELECT * FROM wallet_ledger
WHERE user_id = 1234
AND biz_type = 'rent_payment'
ORDER BY created_at DESC
LIMIT 50;
```
### 3.3 添加缺失索引(如果需要)
```sql
-- 示例:为常用查询组合添加联合索引
ALTER TABLE rental_orders
ADD INDEX idx_status_handoff_created (status, handoff_status, created_at);
-- 为管理后台查询优化
ALTER TABLE wallet_ledger
ADD INDEX idx_created_biz_type (created_at, biz_type);
```
## 四、压力测试执行
### 4.1 使用 Go 压测工具
```bash
cd scripts
# 编译压测工具
go build -o stress_test stress_test.go
# 场景1: 商品列表查询(高频读)
./stress_test -url http://localhost:8080 -c 50 -d 60 -s list_listings
# 场景2: 订单创建(写操作)
./stress_test -url http://localhost:8080 -c 20 -d 60 -s create_order
# 场景3: 钱包流水查询
./stress_test -url http://localhost:8080 -c 30 -d 60 -s wallet
# 场景4: 混合场景(模拟真实流量)
./stress_test -url http://localhost:8080 -c 100 -d 300 -s mixed
```
### 4.2 使用 Apache Bench (ab)
```bash
# 简单的商品列表查询压测
ab -n 10000 -c 100 http://localhost:8080/api/listings?page=1&page_size=20
# 健康检查接口压测
ab -n 50000 -c 200 http://localhost:8080/health
```
### 4.3 使用 wrk
```bash
# 安装 wrk
brew install wrk # macOS
# sudo apt install wrk # Ubuntu
# 基础压测
wrk -t4 -c100 -d60s http://localhost:8080/api/listings
# 使用脚本进行复杂场景测试
wrk -t4 -c100 -d60s -s scripts/wrk_scenario.lua http://localhost:8080
```
创建 `scripts/wrk_scenario.lua`
```lua
-- 模拟不同的查询参数
counter = 0
request = function()
counter = counter + 1
page = (counter % 10) + 1
path = "/api/listings?page=" .. page .. "&page_size=20"
return wrk.format("GET", path)
end
```
## 五、性能监控
### 5.1 数据库性能监控
```sql
-- 实时查看正在执行的查询
SHOW FULL PROCESSLIST;
-- 查看慢查询日志
docker exec hfb-mysql tail -f /var/log/mysql/slow.log
-- 查看表锁情况
SHOW OPEN TABLES WHERE In_use > 0;
-- 查看InnoDB状态
SHOW ENGINE INNODB STATUS;
-- 查看连接数
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Max_used_connections';
```
### 5.2 应用性能监控
在压测期间,监控后端日志:
```bash
# 实时查看后端日志
tail -f backend/logs/app-*.log | grep -E "ERROR|WARN|latency"
# 监控容器资源使用
docker stats hfb-backend hfb-mysql hfb-redis
```
### 5.3 系统资源监控
```bash
# CPU和内存使用
top -p $(pgrep -f "go run")
# 网络连接数
netstat -an | grep :8080 | wc -l
# 查看打开的文件描述符
lsof -p $(pgrep -f "go run") | wc -l
```
## 六、性能指标基准
### 6.1 响应时间目标
| 接口类型 | P50 | P95 | P99 |
|---------|-----|-----|-----|
| 商品列表查询 | < 50ms | < 100ms | < 200ms |
| 订单详情查询 | < 30ms | < 80ms | < 150ms |
| 钱包流水查询 | < 40ms | < 100ms | < 200ms |
| 创建订单 | < 100ms | < 300ms | < 500ms |
| 支付处理 | < 200ms | < 500ms | < 1000ms |
### 6.2 吞吐量目标
- **读操作**:单机 QPS > 1000
- **写操作**:单机 QPS > 200
- **混合场景**:单机 QPS > 500
### 6.3 数据库查询目标
- **简单查询**< 10ms
- **联表查询**< 50ms
- **复杂聚合**< 100ms
## 七、常见性能瓶颈与优化
### 7.1 数据库层面
#### 问题1:商品列表查询慢
**症状:** `SELECT * FROM rental_listings WHERE status = 'active'` 耗时超过 100ms
**优化方案:**
```sql
-- 1. 添加覆盖索引
ALTER TABLE rental_listings
ADD INDEX idx_status_review_published_cover (
status, review_status, published_at, id, price, deposit_amount
);
-- 2. 避免 SELECT *,只查询需要的字段
SELECT id, owner_id, price, deposit_amount, published_at
FROM rental_listings
WHERE status = 'active' AND review_status = 'approved'
ORDER BY published_at DESC
LIMIT 20;
```
#### 问题2:用户订单分页查询慢
**症状:** 大偏移量分页(page > 100)性能下降
**优化方案:**
```sql
-- 使用游标分页代替 OFFSET
SELECT * FROM rental_orders
WHERE renter_id = ?
AND id < ? -- 上一页最后一条的ID
ORDER BY id DESC
LIMIT 20;
```
在代码中实现:
```go
// 使用游标分页
func (r *Repository) ListOrdersCursor(userID, lastID uint64, limit int) ([]Order, error) {
query := `SELECT * FROM rental_orders
WHERE renter_id = ? AND id < ?
ORDER BY id DESC LIMIT ?`
if lastID == 0 {
lastID = ^uint64(0) // Max uint64
}
// ...
}
```
#### 问题3:钱包流水查询慢(10万+数据)
**优化方案:**
```sql
-- 1. 确保有复合索引
ALTER TABLE wallet_ledger
ADD INDEX idx_user_created_desc (user_id, created_at DESC);
-- 2. 分区表(适用于超大数据量)
ALTER TABLE wallet_ledger
PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
-- 3. 归档历史数据
CREATE TABLE wallet_ledger_archive LIKE wallet_ledger;
INSERT INTO wallet_ledger_archive
SELECT * FROM wallet_ledger
WHERE created_at < DATE_SUB(NOW(), INTERVAL 6 MONTH);
```
### 7.2 应用层面
#### 问题1N+1 查询问题
**症状:** 商品列表查询后,循环查询关联的账号信息
**优化方案:**
```go
// 错误做法:N+1查询
for _, listing := range listings {
account, _ := repo.GetAccount(listing.AccountID)
listing.Account = account
}
// 正确做法:预加载
func (r *Repository) ListWithAccounts(filter ListingFilter) ([]Listing, error) {
query := `
SELECT
rl.*,
ga.title as account_title,
ga.rank_level,
ga.server_region
FROM rental_listings rl
LEFT JOIN game_accounts ga ON rl.account_id = ga.id
WHERE rl.status = ?
ORDER BY rl.published_at DESC
LIMIT ?
`
// ...
}
```
#### 问题2:缓存缺失
**优化方案:**
```go
// 为热点数据添加Redis缓存
func (s *Service) GetListing(id uint64) (*Listing, error) {
cacheKey := fmt.Sprintf("listing:%d", id)
// 1. 尝试从缓存读取
if cached, err := s.redis.Get(ctx, cacheKey).Bytes(); err == nil {
var listing Listing
json.Unmarshal(cached, &listing)
return &listing, nil
}
// 2. 缓存未命中,从数据库读取
listing, err := s.repo.GetByID(id)
if err != nil {
return nil, err
}
// 3. 写入缓存
data, _ := json.Marshal(listing)
s.redis.Set(ctx, cacheKey, data, 10*time.Minute)
return listing, nil
}
```
#### 问题3:数据库连接池耗尽
**优化方案:**
```go
// 在 database/mysql.go 中优化连接池配置
db.SetMaxOpenConns(100) // 最大连接数
db.SetMaxIdleConns(20) // 空闲连接数
db.SetConnMaxLifetime(time.Hour) // 连接最大生命周期
db.SetConnMaxIdleTime(10 * time.Minute) // 空闲连接超时
```
### 7.3 Redis 优化
```bash
# 监控 Redis 性能
redis-cli --latency
redis-cli --stat
# 查看慢查询
redis-cli SLOWLOG GET 10
# 查看内存使用
redis-cli INFO memory
```
**配置优化:**
```redis
# 最大内存限制
maxmemory 2gb
# 内存淘汰策略
maxmemory-policy allkeys-lru
# 持久化配置(开发环境可以关闭以提升性能)
save ""
appendonly no
```
## 八、特定场景测试
### 8.1 订单高峰测试
模拟秒杀或活动高峰期:
```bash
# 同时创建1000个订单
./stress_test -url http://localhost:8080 -c 100 -d 10 -s create_order
```
**预期检查:**
- 数据库连接池是否耗尽
- 是否出现死锁
- 钱包余额扣减是否正确(需要事务隔离)
### 8.2 聊天消息压测
```bash
# 模拟100个用户同时发送消息
./stress_test -url http://localhost:8080 -c 100 -d 60 -s chat
```
**预期检查:**
- WebSocket 连接数限制
- 消息写入速度
- 未读消息计数准确性
### 8.3 大数据量查询
```sql
-- 测试后台钱包流水导出(大数据量)
SELECT * FROM wallet_ledger
WHERE created_at >= '2024-01-01'
ORDER BY created_at DESC;
-- 超时检查
SET SESSION max_execution_time = 30000; -- 30秒超时
```
## 九、压测后清理
### 9.1 清理测试数据
```sql
-- 谨慎执行!会删除所有测试数据
DELETE FROM wallet_ledger WHERE id > 100;
DELETE FROM rental_orders WHERE id > 100;
DELETE FROM rental_listings WHERE id > 100;
DELETE FROM game_accounts WHERE id > 100;
DELETE FROM users WHERE id > 1000;
-- 重置自增ID
ALTER TABLE users AUTO_INCREMENT = 1001;
ALTER TABLE rental_orders AUTO_INCREMENT = 101;
```
### 9.2 恢复配置
```bash
# 恢复开发环境配置
cd backend
cp .env.example .env
# 重启服务
./scripts/dev.sh
```
## 十、持续监控建议
### 10.1 生产环境监控
推荐集成:
- **APM**: New Relic / Datadog
- **日志**: ELK Stack / Grafana Loki
- **监控**: Prometheus + Grafana
- **告警**: PagerDuty / 企业微信
### 10.2 关键指标
**应用层:**
- API 响应时间(P50/P95/P99
- QPS / TPS
- 错误率
- 慢查询数量
**数据库层:**
- 连接数
- 慢查询数
- 锁等待时间
- InnoDB 缓存命中率
**系统层:**
- CPU 使用率
- 内存使用率
- 磁盘 IO
- 网络带宽
## 十一、性能优化 Checklist
- [ ] 数据库索引覆盖所有常用查询
- [ ] 消除 N+1 查询问题
- [ ] 热点数据使用 Redis 缓存
- [ ] 数据库连接池配置合理
- [ ] 分页查询使用游标而非 OFFSET
- [ ] 大数据量表考虑分区
- [ ] 历史数据定期归档
- [ ] 慢查询日志监控告警
- [ ] 数据库读写分离(如适用)
- [ ] CDN 加速静态资源
## 附录
### A. 压测命令速查
```bash
# 启动测试环境
docker-compose -f deploy/docker-compose.dev.yml up -d
cd backend && go run ./cmd/api
# 生成测试数据
docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < scripts/load_test_data.sql
# 执行压测
cd scripts
go build -o stress_test stress_test.go
./stress_test -url http://localhost:8080 -c 100 -d 60 -s mixed
# 监控性能
docker stats
docker exec hfb-mysql mysqladmin -uhfb -psecret processlist
```
### B. 参考资料
- [MySQL 性能优化最佳实践](https://dev.mysql.com/doc/refman/8.0/en/optimization.html)
- [Go 性能优化](https://github.com/dgryski/go-perfbook)
- [Gin 框架性能调优](https://gin-gonic.com/docs/benchmarks/)