Files
hfb_sys/scripts/stress_test.sh
T
2026-06-09 22:38:35 +08:00

483 lines
13 KiB
Bash
Executable File
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.
#!/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 load_stress.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