13 KiB
13 KiB
压力测试指南
本文档提供完整的压力测试方案,用于评估系统在大数据量和高并发场景下的性能表现。
一、测试环境准备
1.1 硬件配置建议
最低配置:
- CPU: 4核
- 内存: 8GB
- 磁盘: SSD 50GB
推荐配置:
- CPU: 8核+
- 内存: 16GB+
- 磁盘: SSD 100GB+
- MySQL: 独立部署,开启慢查询日志
1.2 数据库优化配置
在 deploy/docker-compose.dev.yml 中调整 MySQL 配置:
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 中调整:
# 数据库连接池
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 执行数据生成脚本
# 连接到数据库容器
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 验证数据生成
-- 查看数据统计
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 自定义数据量
修改脚本底部的调用参数:
-- 根据需要调整数量
CALL generate_users(50000); -- 生成5万用户
CALL generate_listings(200000); -- 生成20万商品
CALL generate_orders(100000); -- 生成10万订单
CALL generate_wallet_ledger(500000); -- 生成50万流水
三、索引优化验证
3.1 检查现有索引
-- 查看订单表索引
SHOW INDEX FROM rental_orders;
-- 查看钱包流水索引
SHOW INDEX FROM wallet_ledger;
-- 查看商品表索引
SHOW INDEX FROM rental_listings;
3.2 分析慢查询
-- 分析商品列表查询
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 添加缺失索引(如果需要)
-- 示例:为常用查询组合添加联合索引
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 压测工具
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)
# 简单的商品列表查询压测
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
# 安装 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:
-- 模拟不同的查询参数
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 数据库性能监控
-- 实时查看正在执行的查询
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 应用性能监控
在压测期间,监控后端日志:
# 实时查看后端日志
tail -f backend/logs/app-*.log | grep -E "ERROR|WARN|latency"
# 监控容器资源使用
docker stats hfb-backend hfb-mysql hfb-redis
5.3 系统资源监控
# 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
优化方案:
-- 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)性能下降
优化方案:
-- 使用游标分页代替 OFFSET
SELECT * FROM rental_orders
WHERE renter_id = ?
AND id < ? -- 上一页最后一条的ID
ORDER BY id DESC
LIMIT 20;
在代码中实现:
// 使用游标分页
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万+数据)
优化方案:
-- 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 查询问题
症状: 商品列表查询后,循环查询关联的账号信息
优化方案:
// 错误做法: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:缓存缺失
优化方案:
// 为热点数据添加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:数据库连接池耗尽
优化方案:
// 在 database/mysql.go 中优化连接池配置
db.SetMaxOpenConns(100) // 最大连接数
db.SetMaxIdleConns(20) // 空闲连接数
db.SetConnMaxLifetime(time.Hour) // 连接最大生命周期
db.SetConnMaxIdleTime(10 * time.Minute) // 空闲连接超时
7.3 Redis 优化
# 监控 Redis 性能
redis-cli --latency
redis-cli --stat
# 查看慢查询
redis-cli SLOWLOG GET 10
# 查看内存使用
redis-cli INFO memory
配置优化:
# 最大内存限制
maxmemory 2gb
# 内存淘汰策略
maxmemory-policy allkeys-lru
# 持久化配置(开发环境可以关闭以提升性能)
save ""
appendonly no
八、特定场景测试
8.1 订单高峰测试
模拟秒杀或活动高峰期:
# 同时创建1000个订单
./stress_test -url http://localhost:8080 -c 100 -d 10 -s create_order
预期检查:
- 数据库连接池是否耗尽
- 是否出现死锁
- 钱包余额扣减是否正确(需要事务隔离)
8.2 聊天消息压测
# 模拟100个用户同时发送消息
./stress_test -url http://localhost:8080 -c 100 -d 60 -s chat
预期检查:
- WebSocket 连接数限制
- 消息写入速度
- 未读消息计数准确性
8.3 大数据量查询
-- 测试后台钱包流水导出(大数据量)
SELECT * FROM wallet_ledger
WHERE created_at >= '2024-01-01'
ORDER BY created_at DESC;
-- 超时检查
SET SESSION max_execution_time = 30000; -- 30秒超时
九、压测后清理
9.1 清理测试数据
-- 谨慎执行!会删除所有测试数据
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 恢复配置
# 恢复开发环境配置
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. 压测命令速查
# 启动测试环境
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