# 压力测试指南 本文档提供完整的压力测试方案,用于评估系统在大数据量和高并发场景下的性能表现。 ## 一、测试环境准备 ### 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 应用层面 #### 问题1:N+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/)