增加测试 修复错误

This commit is contained in:
yml
2026-06-05 22:01:14 +08:00
parent 402c19320d
commit b04fb629cb
6 changed files with 2042 additions and 1 deletions
+606
View File
@@ -0,0 +1,606 @@
# 压力测试指南
本文档提供完整的压力测试方案,用于评估系统在大数据量和高并发场景下的性能表现。
## 一、测试环境准备
### 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/)
+242
View File
@@ -0,0 +1,242 @@
# 压力测试方案总结
## 快速开始
### 1. 生成测试数据
```bash
./scripts/stress_test.sh data
```
### 2. 执行压力测试
```bash
# 混合场景测试(推荐)
./scripts/stress_test.sh test -c 100 -d 60 -s mixed
# 商品列表查询测试
./scripts/stress_test.sh test -c 200 -d 120 -s list_listings
# 订单创建测试
./scripts/stress_test.sh test -c 50 -d 60 -s create_order
```
### 3. 查看报告
```bash
./scripts/stress_test.sh report
```
### 4. 清理数据
```bash
./scripts/stress_test.sh clean
```
## 已创建的压测工具
### 1. 数据生成脚本
**文件**: `scripts/load_test_data.sql`
**功能**:
- 批量生成10,000个用户
- 批量生成50,000个租号商品
- 批量生成30,000个订单
- 批量生成100,000条钱包流水
- 批量生成50,000条聊天消息
**特点**:
- 使用存储过程提高生成效率
- 每1000条自动提交一次
- 模拟真实的业务数据分布
- 支持自定义数量
### 2. Go压测工具
**文件**: `scripts/stress_test.go`
**测试场景**:
- `list_listings`: 商品列表查询(高频读)
- `create_order`: 订单创建(写操作)
- `wallet`: 钱包流水查询
- `chat`: 聊天消息查询
- `mixed`: 混合场景(模拟真实流量比例)
**使用示例**:
```bash
cd scripts
go build -o stress_test stress_test.go
./stress_test -url http://localhost:8080 -c 100 -d 60 -s mixed
```
### 3. 一键压测脚本
**文件**: `scripts/stress_test.sh`
**功能**:
- `data`: 生成测试数据
- `test`: 执行压力测试
- `monitor`: 监控系统性能
- `clean`: 清理测试数据
- `report`: 生成压测报告
- `all`: 执行完整流程
### 4. 压测指南文档
**文件**: `docs/stress-test-guide.md`
**包含内容**:
- 测试环境准备
- 数据库优化配置
- 索引优化建议
- 性能监控方法
- 常见瓶颈与优化方案
- 持续监控建议
## 核心压力点分析
### 高频读场景
1. **商品列表查询**:
- 带复杂筛选条件(状态、审核状态、价格区间)
- 需要优化索引: `idx_rental_listings_filter`
- 建议添加Redis缓存
2. **订单列表查询**:
- 多角色视角(租客、号主)
- 关联查询多张表
- 优化: 使用游标分页代替OFFSET
3. **钱包流水查询**:
- 数据量大(10万+
- 需要按时间倒序
- 优化: 复合索引 `idx_user_created_desc`
### 高频写场景
1. **订单创建和支付**:
- 涉及多表事务
- 钱包扣款+订单创建+通知
- 需要确保事务隔离级别
2. **聊天消息发送**:
- 高并发写入
- 需要更新会话最后消息时间
- 考虑消息队列异步处理
### 数据库优化要点
**关键索引**:
```sql
-- 商品查询
ALTER TABLE rental_listings
ADD INDEX idx_status_review_published (status, review_status, published_at DESC);
-- 订单查询
ALTER TABLE rental_orders
ADD INDEX idx_renter_status_created (renter_id, status, created_at DESC);
ADD INDEX idx_owner_status_created (owner_id, status, created_at DESC);
-- 钱包流水
ALTER TABLE wallet_ledger
ADD INDEX idx_user_created_desc (user_id, created_at DESC);
ADD INDEX idx_user_biz_created (user_id, biz_type, created_at DESC);
```
**连接池配置**:
```bash
DB_MAX_OPEN_CONNS=100
DB_MAX_IDLE_CONNS=20
DB_CONN_MAX_LIFETIME=3600
```
## 性能目标
### 响应时间
- 商品列表: P95 < 100ms
- 订单查询: P95 < 80ms
- 钱包流水: P95 < 100ms
- 创建订单: P95 < 300ms
### 吞吐量
- 读操作: QPS > 1000
- 写操作: QPS > 200
- 混合场景: QPS > 500
## 监控命令
### 实时监控
```bash
# 容器资源使用
docker stats hfb-backend hfb-mysql hfb-redis
# MySQL连接数
docker exec hfb-mysql mysql -uhfb -psecret -e "SHOW STATUS LIKE 'Threads_connected';"
# 慢查询
docker exec hfb-mysql mysql -uhfb -psecret -e "SHOW STATUS LIKE 'Slow_queries';"
# 正在执行的查询
docker exec hfb-mysql mysql -uhfb -psecret -e "SHOW FULL PROCESSLIST;"
```
### 慢查询分析
```bash
# 查看慢查询日志
docker exec hfb-mysql tail -100 /var/log/mysql/slow.log
```
## 常见问题排查
### 问题1: 商品列表查询慢
**现象**: 查询耗时 > 100ms
**排查**:
```sql
EXPLAIN SELECT * FROM rental_listings
WHERE status = 'active' AND review_status = 'approved'
ORDER BY published_at DESC LIMIT 20;
```
**优化**: 添加覆盖索引,避免回表
### 问题2: 大偏移量分页慢
**现象**: page > 100 时性能急剧下降
**优化**: 使用游标分页
```sql
SELECT * FROM rental_orders
WHERE renter_id = ? AND id < ?
ORDER BY id DESC LIMIT 20;
```
### 问题3: 连接池耗尽
**现象**: 大量 "too many connections" 错误
**优化**:
- 增加 `max_connections`
- 优化查询,减少慢查询
- 检查是否有连接泄漏
## 下一步优化建议
1. **缓存层**: Redis缓存热点数据(商品详情、用户信息)
2. **读写分离**: 主库写入,从库读取
3. **分库分表**: 当单表超过千万级时考虑
4. **异步处理**: 使用消息队列处理非关键路径操作
5. **CDN加速**: 静态资源和图片使用CDN
## 完整流程示例
```bash
# 1. 启动开发环境
./scripts/dev.sh
# 2. 生成测试数据
./scripts/stress_test.sh data
# 3. 执行压测
./scripts/stress_test.sh test -c 100 -d 300 -s mixed
# 4. 监控(另开终端)
./scripts/stress_test.sh monitor
# 5. 查看报告
./scripts/stress_test.sh report
# 6. 清理数据
./scripts/stress_test.sh clean
```
详细文档请查看: `docs/stress-test-guide.md`