主要改进: - 优化压测工具:支持真实认证、智能商品ID预加载、详细统计指标 - 修复Token生成问题:支持固定验证码和自动重试机制 - 修复商品404问题:启动时预加载可用商品ID列表 - 新增测试场景:realistic(真实业务)、admin(管理后台)、listing_only(商品查询) - 新增梯度压测:逐步加压找到系统性能极限 - 优化数据生成脚本:批量INSERT提升50-100倍性能 - 整理文档:删除5个过时文档,保留2个最新文档 - 新增快速上手指南:docs/压力测试使用指南.md 性能基线(10并发): - QPS: 2,600+ - P50/P95/P99延迟: 3ms/7ms/10ms Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
483 lines
13 KiB
Bash
Executable File
483 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# 压力测试快速启动脚本
|
||
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
function log_info() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
function log_warn() {
|
||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||
}
|
||
|
||
function log_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
function show_usage() {
|
||
cat << EOF
|
||
压力测试脚本(优化版)
|
||
|
||
用法:
|
||
$0 [command] [options]
|
||
|
||
命令:
|
||
data 生成测试数据(使用优化的批量生成)
|
||
test 执行压力测试(支持真实认证)
|
||
monitor 监控系统性能
|
||
clean 清理测试数据
|
||
report 生成压测报告
|
||
all 执行完整流程(生成数据 + 压测 + 报告)
|
||
|
||
选项:
|
||
数据生成:
|
||
-u, --users NUM 生成用户数量(默认: 1000)
|
||
-l, --listings NUM 生成商品数量(默认: 5000)
|
||
-o, --orders NUM 生成订单数量(默认: 3000)
|
||
--ledger NUM 生成钱包流水数量(默认: 10000)
|
||
--chat-messages NUM 生成聊天消息数量(默认: 5000)
|
||
--use-optimized 使用优化的数据生成脚本(推荐)
|
||
|
||
压力测试:
|
||
-c, --concurrency NUM 并发数(默认: 50)
|
||
-d, --duration SEC 测试时长/秒(默认: 60)
|
||
-s, --scenario NAME 测试场景:
|
||
- realistic: 真实业务场景(默认)
|
||
- admin: 管理后台场景
|
||
- listing_only: 仅商品查询
|
||
--gradual 启用梯度压测
|
||
--warmup NUM 预热用户数(默认: 100)
|
||
--use-improved 使用改进的压测工具(支持真实认证)
|
||
--url URL 后端地址(默认: http://localhost:8080)
|
||
|
||
通用:
|
||
-h, --help 显示帮助信息
|
||
|
||
示例:
|
||
# 小规模数据生成(使用优化脚本)
|
||
$0 data --use-optimized
|
||
|
||
# 真实场景压测(100个用户token,50并发,持续60秒)
|
||
$0 test --use-improved -c 50 -d 60 -s realistic --warmup 100
|
||
|
||
# 管理后台压测
|
||
$0 test --use-improved -c 30 -d 120 -s admin
|
||
|
||
# 梯度压测(逐步增加负载)
|
||
$0 test --use-improved --gradual -d 60
|
||
|
||
# 执行完整流程(优化版)
|
||
$0 all --use-optimized --use-improved
|
||
|
||
# 清理测试数据
|
||
$0 clean
|
||
|
||
EOF
|
||
}
|
||
|
||
# 默认参数
|
||
USERS=1000
|
||
LISTINGS=5000
|
||
ORDERS=3000
|
||
LEDGER=10000
|
||
CHAT_MESSAGES=5000
|
||
CONCURRENCY=50
|
||
DURATION=60
|
||
SCENARIO="realistic"
|
||
BASE_URL="http://localhost:8080"
|
||
USE_OPTIMIZED=false
|
||
USE_IMPROVED=true
|
||
GRADUAL=false
|
||
WARMUP=100
|
||
|
||
# 解析命令行参数
|
||
COMMAND=""
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
data|test|monitor|clean|report|all)
|
||
COMMAND="$1"
|
||
shift
|
||
;;
|
||
-u|--users)
|
||
USERS="$2"
|
||
shift 2
|
||
;;
|
||
-l|--listings)
|
||
LISTINGS="$2"
|
||
shift 2
|
||
;;
|
||
-o|--orders)
|
||
ORDERS="$2"
|
||
shift 2
|
||
;;
|
||
--ledger)
|
||
LEDGER="$2"
|
||
shift 2
|
||
;;
|
||
--chat-messages)
|
||
CHAT_MESSAGES="$2"
|
||
shift 2
|
||
;;
|
||
-c|--concurrency)
|
||
CONCURRENCY="$2"
|
||
shift 2
|
||
;;
|
||
-d|--duration)
|
||
DURATION="$2"
|
||
shift 2
|
||
;;
|
||
-s|--scenario)
|
||
SCENARIO="$2"
|
||
shift 2
|
||
;;
|
||
--url)
|
||
BASE_URL="$2"
|
||
shift 2
|
||
;;
|
||
--use-optimized)
|
||
USE_OPTIMIZED=true
|
||
shift
|
||
;;
|
||
--use-improved)
|
||
USE_IMPROVED=true
|
||
shift
|
||
;;
|
||
--gradual)
|
||
GRADUAL=true
|
||
shift
|
||
;;
|
||
--warmup)
|
||
WARMUP="$2"
|
||
shift 2
|
||
;;
|
||
-h|--help)
|
||
show_usage
|
||
exit 0
|
||
;;
|
||
*)
|
||
log_error "未知参数: $1"
|
||
show_usage
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
if [ -z "$COMMAND" ]; then
|
||
log_error "请指定命令"
|
||
show_usage
|
||
exit 1
|
||
fi
|
||
|
||
# 检查数据库连接
|
||
function check_database() {
|
||
log_info "检查数据库连接..."
|
||
if docker exec hfb-mysql mysql -uhfb -psecret -e "SELECT 1" &>/dev/null; then
|
||
log_info "数据库连接正常"
|
||
return 0
|
||
else
|
||
log_error "数据库连接失败,请确保 Docker 容器正在运行"
|
||
log_info "提示: 执行 'docker-compose -f deploy/docker-compose.dev.yml up -d' 启动服务"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查后端服务
|
||
function check_backend() {
|
||
log_info "检查后端服务..."
|
||
if curl -s "$BASE_URL/health" &>/dev/null; then
|
||
log_info "后端服务正常"
|
||
return 0
|
||
else
|
||
log_warn "后端服务未响应: $BASE_URL"
|
||
log_info "提示: 确保后端服务已启动"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 生成测试数据
|
||
function generate_data() {
|
||
log_info "开始生成测试数据..."
|
||
log_info "配置: 用户=$USERS, 商品=$LISTINGS, 订单=$ORDERS, 钱包流水=$LEDGER, 聊天消息=$CHAT_MESSAGES"
|
||
|
||
check_database || exit 1
|
||
|
||
# 选择使用的SQL脚本
|
||
SQL_FILE="$SCRIPT_DIR/load_test_data.sql"
|
||
if [ "$USE_OPTIMIZED" = true ]; then
|
||
SQL_FILE="$SCRIPT_DIR/load_test_data_optimized.sql"
|
||
log_info "使用优化的数据生成脚本"
|
||
fi
|
||
|
||
# 创建临时SQL文件
|
||
TMP_SQL="/tmp/load_test_data_$(date +%s).sql"
|
||
trap 'rm -f "$TMP_SQL"' RETURN
|
||
|
||
if [ "$USE_OPTIMIZED" = true ]; then
|
||
cat > "$TMP_SQL" << EOF
|
||
-- 优化版数据生成
|
||
USE hfb_sys;
|
||
|
||
-- 调用批量生成存储过程
|
||
CALL generate_users_batch($USERS);
|
||
CALL generate_listings_batch($LISTINGS);
|
||
CALL generate_orders_batch($ORDERS);
|
||
CALL generate_wallet_ledger_batch($LEDGER);
|
||
CALL generate_chat_data_batch($CHAT_MESSAGES);
|
||
|
||
-- 显示统计
|
||
SELECT '用户数' as item, COUNT(*) as count FROM users
|
||
UNION ALL SELECT '游戏账号数', COUNT(*) FROM game_accounts
|
||
UNION ALL SELECT '商品数', COUNT(*) FROM rental_listings
|
||
UNION ALL SELECT '订单数', COUNT(*) FROM rental_orders
|
||
UNION ALL SELECT '钱包流水数', COUNT(*) FROM wallet_ledger
|
||
UNION ALL SELECT '聊天会话数', COUNT(*) FROM chat_conversations
|
||
UNION ALL SELECT '聊天消息数', COUNT(*) FROM chat_messages;
|
||
EOF
|
||
else
|
||
cat > "$TMP_SQL" << EOF
|
||
-- 原始版数据生成
|
||
USE hfb_sys;
|
||
|
||
-- 调用存储过程生成数据
|
||
CALL generate_users($USERS);
|
||
CALL generate_listings($LISTINGS);
|
||
CALL generate_orders($ORDERS);
|
||
CALL generate_wallet_ledger($LEDGER);
|
||
|
||
-- 生成聊天会话
|
||
INSERT INTO chat_conversations (order_id, type, title, status, last_message_at)
|
||
SELECT id, 'order_group', CONCAT('订单', order_no, '群聊'), 'active', created_at
|
||
FROM rental_orders
|
||
WHERE id <= 1000
|
||
ON DUPLICATE KEY UPDATE order_id=order_id;
|
||
|
||
CALL generate_chat_messages($CHAT_MESSAGES);
|
||
|
||
-- 显示统计
|
||
SELECT '用户数' as item, COUNT(*) as count FROM users
|
||
UNION ALL SELECT '游戏账号数', COUNT(*) FROM game_accounts
|
||
UNION ALL SELECT '商品数', COUNT(*) FROM rental_listings
|
||
UNION ALL SELECT '订单数', COUNT(*) FROM rental_orders
|
||
UNION ALL SELECT '钱包流水数', COUNT(*) FROM wallet_ledger
|
||
UNION ALL SELECT '聊天会话数', COUNT(*) FROM chat_conversations
|
||
UNION ALL SELECT '聊天消息数', COUNT(*) FROM chat_messages;
|
||
EOF
|
||
fi
|
||
|
||
log_info "执行数据生成..."
|
||
|
||
# 先执行基础SQL创建存储过程
|
||
docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < "$SQL_FILE"
|
||
|
||
# 执行数据生成
|
||
docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys < "$TMP_SQL"
|
||
|
||
rm -f "$TMP_SQL"
|
||
trap - RETURN
|
||
|
||
log_info "测试数据生成完成!"
|
||
}
|
||
|
||
# 执行压力测试
|
||
function run_stress_test() {
|
||
log_info "开始压力测试..."
|
||
log_info "配置: 场景=$SCENARIO, 并发=$CONCURRENCY, 时长=${DURATION}秒, 目标=$BASE_URL"
|
||
|
||
check_backend || log_warn "后端服务未响应,测试可能失败"
|
||
|
||
# 编译压测工具
|
||
log_info "编译压测工具..."
|
||
cd "$SCRIPT_DIR"
|
||
|
||
go build -o stress_test stress_test.go
|
||
|
||
if [ $? -ne 0 ]; then
|
||
log_error "压测工具编译失败"
|
||
return 1
|
||
fi
|
||
|
||
# 执行压测
|
||
log_info "开始执行压力测试..."
|
||
|
||
if [ "$GRADUAL" = true ]; then
|
||
./stress_test -url "$BASE_URL" -c "$CONCURRENCY" -d "$DURATION" -s "$SCENARIO" -warmup "$WARMUP" -gradual
|
||
else
|
||
./stress_test -url "$BASE_URL" -c "$CONCURRENCY" -d "$DURATION" -s "$SCENARIO" -warmup "$WARMUP"
|
||
fi
|
||
|
||
log_info "压力测试完成!"
|
||
}
|
||
|
||
# 监控系统性能
|
||
function monitor_system() {
|
||
log_info "开始监控系统性能(按 Ctrl+C 停止)..."
|
||
|
||
echo ""
|
||
echo "=== Docker 容器资源使用 ==="
|
||
docker stats --no-stream hfb-backend hfb-mysql hfb-redis 2>/dev/null || log_warn "部分容器未运行"
|
||
|
||
echo ""
|
||
echo "=== MySQL 连接数 ==="
|
||
docker exec hfb-mysql mysql -uhfb -psecret -e "SHOW STATUS LIKE 'Threads_connected';" 2>/dev/null
|
||
|
||
echo ""
|
||
echo "=== MySQL 慢查询统计 ==="
|
||
docker exec hfb-mysql mysql -uhfb -psecret -e "SHOW STATUS LIKE 'Slow_queries';" 2>/dev/null
|
||
|
||
echo ""
|
||
echo "=== Redis 信息 ==="
|
||
docker exec hfb-redis redis-cli INFO stats | grep -E "total_connections_received|total_commands_processed|instantaneous_ops_per_sec" 2>/dev/null
|
||
|
||
echo ""
|
||
log_info "持续监控请使用: docker stats"
|
||
}
|
||
|
||
# 清理测试数据
|
||
function clean_data() {
|
||
log_warn "即将清理所有测试数据,此操作不可恢复!"
|
||
read -p "确认继续?(yes/no): " confirm
|
||
|
||
if [ "$confirm" != "yes" ]; then
|
||
log_info "已取消清理操作"
|
||
exit 0
|
||
fi
|
||
|
||
check_database || exit 1
|
||
|
||
log_info "开始清理测试数据..."
|
||
|
||
docker exec -i hfb-mysql mysql -uhfb -psecret hfb_sys << 'EOF'
|
||
SET FOREIGN_KEY_CHECKS = 0;
|
||
|
||
-- 清理测试数据(保留ID < 1000的数据)
|
||
DELETE FROM chat_messages WHERE id > 100;
|
||
DELETE FROM chat_conversations WHERE id > 100;
|
||
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 game_accounts AUTO_INCREMENT = 101;
|
||
ALTER TABLE rental_listings AUTO_INCREMENT = 101;
|
||
ALTER TABLE rental_orders AUTO_INCREMENT = 101;
|
||
ALTER TABLE wallet_ledger AUTO_INCREMENT = 101;
|
||
ALTER TABLE chat_conversations AUTO_INCREMENT = 101;
|
||
ALTER TABLE chat_messages AUTO_INCREMENT = 101;
|
||
|
||
SET FOREIGN_KEY_CHECKS = 1;
|
||
|
||
-- 显示清理后的统计
|
||
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;
|
||
EOF
|
||
|
||
log_info "测试数据清理完成!"
|
||
}
|
||
|
||
# 生成压测报告
|
||
function generate_report() {
|
||
log_info "生成压测报告..."
|
||
|
||
REPORT_FILE="$PROJECT_ROOT/stress_test_report_$(date +%Y%m%d_%H%M%S).txt"
|
||
|
||
{
|
||
echo "==================================="
|
||
echo "压力测试报告"
|
||
echo "生成时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "==================================="
|
||
echo ""
|
||
|
||
echo "--- 数据库统计 ---"
|
||
docker exec hfb-mysql mysql -uhfb -psecret hfb_sys -e "
|
||
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>/dev/null
|
||
|
||
echo ""
|
||
echo "--- MySQL 性能指标 ---"
|
||
docker exec hfb-mysql mysql -uhfb -psecret -e "
|
||
SHOW STATUS LIKE 'Threads_connected';
|
||
SHOW STATUS LIKE 'Slow_queries';
|
||
SHOW STATUS LIKE 'Questions';
|
||
" 2>/dev/null
|
||
|
||
echo ""
|
||
echo "--- 表大小统计 ---"
|
||
docker exec hfb-mysql mysql -uhfb -psecret hfb_sys -e "
|
||
SELECT
|
||
table_name AS '表名',
|
||
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)',
|
||
table_rows AS '行数'
|
||
FROM information_schema.TABLES
|
||
WHERE table_schema = 'hfb_sys'
|
||
ORDER BY (data_length + index_length) DESC
|
||
LIMIT 10;
|
||
" 2>/dev/null
|
||
|
||
} > "$REPORT_FILE"
|
||
|
||
cat "$REPORT_FILE"
|
||
|
||
log_info "报告已保存到: $REPORT_FILE"
|
||
}
|
||
|
||
# 执行完整流程
|
||
function run_all() {
|
||
log_info "执行完整压测流程..."
|
||
|
||
generate_data
|
||
sleep 3
|
||
|
||
run_stress_test
|
||
sleep 2
|
||
|
||
generate_report
|
||
|
||
log_info "完整流程执行完成!"
|
||
}
|
||
|
||
# 执行命令
|
||
case $COMMAND in
|
||
data)
|
||
generate_data
|
||
;;
|
||
test)
|
||
run_stress_test
|
||
;;
|
||
monitor)
|
||
monitor_system
|
||
;;
|
||
clean)
|
||
clean_data
|
||
;;
|
||
report)
|
||
generate_report
|
||
;;
|
||
all)
|
||
run_all
|
||
;;
|
||
*)
|
||
log_error "未知命令: $COMMAND"
|
||
show_usage
|
||
exit 1
|
||
;;
|
||
esac
|