完成压力测试工具优化和文档整理

主要改进:
- 优化压测工具:支持真实认证、智能商品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>
This commit is contained in:
yml
2026-06-06 01:10:07 +08:00
co-authored by Claude Opus 4.8
parent ec9baada67
commit 082fd908e9
11 changed files with 2759 additions and 752 deletions
+149 -59
View File
@@ -85,12 +85,32 @@ BEGIN
DECLARE account_id_val BIGINT;
DECLARE price_val DECIMAL(12,2);
DECLARE deposit_val DECIMAL(12,2);
DECLARE verified_user_min BIGINT;
DECLARE verified_user_max BIGINT;
DECLARE user_pick BIGINT;
SELECT MIN(id), MAX(id)
INTO verified_user_min, verified_user_max
FROM users
WHERE realname_status = 'verified';
IF verified_user_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的已实名用户';
END IF;
WHILE i <= batch_size DO
-- 随机选择一个用户作为号主(已实名用户)
-- 近似随机选择一个用户作为号主,避免 ORDER BY RAND() 全表排序。
SET user_id_val = NULL;
SET user_pick = verified_user_min + FLOOR(RAND() * (verified_user_max - verified_user_min + 1));
SELECT id INTO user_id_val FROM users
WHERE realname_status = 'verified'
ORDER BY RAND() LIMIT 1;
WHERE id >= user_pick AND realname_status = 'verified'
ORDER BY id LIMIT 1;
IF user_id_val IS NULL THEN
SELECT id INTO user_id_val FROM users
WHERE realname_status = 'verified'
ORDER BY id LIMIT 1;
END IF;
-- 创建游戏账号
INSERT INTO game_accounts (
@@ -120,7 +140,7 @@ BEGIN
ELSE '钻石'
END,
(i % 100) * 10000,
'active'
'published'
);
SET account_id_val = LAST_INSERT_ID();
@@ -141,7 +161,7 @@ BEGIN
CASE
WHEN i % 20 = 0 THEN 'offline'
WHEN i % 15 = 0 THEN 'draft'
ELSE 'active'
ELSE 'published'
END,
CASE
WHEN i % 15 = 0 THEN 'pending'
@@ -177,19 +197,67 @@ BEGIN
DECLARE order_no_val VARCHAR(64);
DECLARE rent_amount_val DECIMAL(12,2);
DECLARE deposit_val DECIMAL(12,2);
DECLARE listing_min BIGINT;
DECLARE listing_max BIGINT;
DECLARE listing_pick BIGINT;
DECLARE verified_user_min BIGINT;
DECLARE verified_user_max BIGINT;
DECLARE user_pick BIGINT;
SELECT MIN(id), MAX(id)
INTO listing_min, listing_max
FROM rental_listings
WHERE status IN ('published', 'active') AND review_status = 'approved';
SELECT MIN(id), MAX(id)
INTO verified_user_min, verified_user_max
FROM users
WHERE realname_status = 'verified';
IF listing_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的已上架商品';
END IF;
IF verified_user_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的已实名用户';
END IF;
WHILE i <= batch_size DO
-- 随机选择一个上架商品
-- 近似随机选择一个上架商品,避免 ORDER BY RAND() 全表排序。
SET listing_id_val = NULL;
SET listing_pick = listing_min + FLOOR(RAND() * (listing_max - listing_min + 1));
SELECT rl.id, rl.account_id, rl.owner_id, rl.price, rl.deposit_amount
INTO listing_id_val, account_id_val, owner_id_val, rent_amount_val, deposit_val
FROM rental_listings rl
WHERE rl.status = 'active' AND rl.review_status = 'approved'
ORDER BY RAND() LIMIT 1;
WHERE rl.id >= listing_pick
AND rl.status IN ('published', 'active')
AND rl.review_status = 'approved'
ORDER BY rl.id LIMIT 1;
-- 随机选择一个租客(不能是号主本人)
IF listing_id_val IS NULL THEN
SELECT rl.id, rl.account_id, rl.owner_id, rl.price, rl.deposit_amount
INTO listing_id_val, account_id_val, owner_id_val, rent_amount_val, deposit_val
FROM rental_listings rl
WHERE rl.status IN ('published', 'active')
AND rl.review_status = 'approved'
ORDER BY rl.id LIMIT 1;
END IF;
-- 近似随机选择一个租客(不能是号主本人)。
SET renter_id_val = NULL;
SET user_pick = verified_user_min + FLOOR(RAND() * (verified_user_max - verified_user_min + 1));
SELECT id INTO renter_id_val FROM users
WHERE id != owner_id_val AND realname_status = 'verified'
ORDER BY RAND() LIMIT 1;
WHERE id >= user_pick AND id != owner_id_val AND realname_status = 'verified'
ORDER BY id LIMIT 1;
IF renter_id_val IS NULL THEN
SELECT id INTO renter_id_val FROM users
WHERE id != owner_id_val AND realname_status = 'verified'
ORDER BY id LIMIT 1;
END IF;
IF renter_id_val IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的租客用户';
END IF;
SET order_no_val = CONCAT('ORD', DATE_FORMAT(NOW(), '%Y%m%d'), LPAD(i, 8, '0'));
SET rent_amount_val = rent_amount_val * 24; -- 24小时租金
@@ -254,14 +322,43 @@ BEGIN
DECLARE order_id_val BIGINT;
DECLARE ledger_no_val VARCHAR(64);
DECLARE amount_val DECIMAL(12,2);
DECLARE user_min BIGINT;
DECLARE user_max BIGINT;
DECLARE order_min BIGINT;
DECLARE order_max BIGINT;
DECLARE user_pick BIGINT;
DECLARE order_pick BIGINT;
SELECT MIN(id), MAX(id) INTO user_min, user_max FROM users;
SELECT MIN(id), MAX(id) INTO order_min, order_max FROM rental_orders;
IF user_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的用户';
END IF;
WHILE i <= batch_size DO
-- 随机选择用户
SELECT id INTO user_id_val FROM users ORDER BY RAND() LIMIT 1;
-- 近似随机选择用户,避免 ORDER BY RAND() 全表排序。
SET user_id_val = NULL;
SET user_pick = user_min + FLOOR(RAND() * (user_max - user_min + 1));
SELECT id INTO user_id_val FROM users
WHERE id >= user_pick
ORDER BY id LIMIT 1;
IF user_id_val IS NULL THEN
SELECT id INTO user_id_val FROM users ORDER BY id LIMIT 1;
END IF;
-- 随机关联订单(50%概率)
IF RAND() > 0.5 THEN
SELECT id INTO order_id_val FROM rental_orders ORDER BY RAND() LIMIT 1;
IF RAND() > 0.5 AND order_min IS NOT NULL THEN
SET order_id_val = NULL;
SET order_pick = order_min + FLOOR(RAND() * (order_max - order_min + 1));
SELECT id INTO order_id_val FROM rental_orders
WHERE id >= order_pick
ORDER BY id LIMIT 1;
IF order_id_val IS NULL THEN
SELECT id INTO order_id_val FROM rental_orders ORDER BY id LIMIT 1;
END IF;
ELSE
SET order_id_val = NULL;
END IF;
@@ -314,14 +411,45 @@ BEGIN
DECLARE i INT DEFAULT 1;
DECLARE conv_id BIGINT;
DECLARE user_id_val BIGINT;
DECLARE conv_min BIGINT;
DECLARE conv_max BIGINT;
DECLARE user_min BIGINT;
DECLARE user_max BIGINT;
DECLARE conv_pick BIGINT;
DECLARE user_pick BIGINT;
SELECT MIN(id), MAX(id) INTO conv_min, conv_max FROM chat_conversations;
SELECT MIN(id), MAX(id) INTO user_min, user_max FROM users;
IF conv_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的聊天会话';
END IF;
IF user_min IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '没有可用的用户';
END IF;
WHILE i <= batch_size DO
-- 随机选择一个会话
SELECT id INTO conv_id FROM chat_conversations ORDER BY RAND() LIMIT 1;
-- 近似随机选择一个会话和发送者,避免 ORDER BY RAND() 全表排序。
SET conv_id = NULL;
SET conv_pick = conv_min + FLOOR(RAND() * (conv_max - conv_min + 1));
SELECT id INTO conv_id FROM chat_conversations
WHERE id >= conv_pick
ORDER BY id LIMIT 1;
IF conv_id IS NULL THEN
SELECT id INTO conv_id FROM chat_conversations ORDER BY id LIMIT 1;
END IF;
IF conv_id IS NOT NULL THEN
-- 随机选择发送者
SELECT id INTO user_id_val FROM users ORDER BY RAND() LIMIT 1;
SET user_id_val = NULL;
SET user_pick = user_min + FLOOR(RAND() * (user_max - user_min + 1));
SELECT id INTO user_id_val FROM users
WHERE id >= user_pick
ORDER BY id LIMIT 1;
IF user_id_val IS NULL THEN
SELECT id INTO user_id_val FROM users ORDER BY id LIMIT 1;
END IF;
INSERT INTO chat_messages (
conversation_id, sender_type, sender_id, sender_role,
@@ -349,46 +477,8 @@ END$$
DELIMITER ;
-- ============================================
-- 执行数据生成(根据需要调整数量)
-- 本文件只创建存储过程,不直接生成数据。
-- 请使用 scripts/stress_test.sh data 按参数生成,避免意外重复造数。
-- ============================================
-- 生成10000个用户
CALL generate_users(10000);
-- 生成50000个商品
CALL generate_listings(50000);
-- 生成30000个订单
CALL generate_orders(30000);
-- 生成100000条钱包流水
CALL generate_wallet_ledger(100000);
-- 为前1000个订单创建会话
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;
-- 生成50000条聊天消息
CALL generate_chat_messages(50000);
-- ============================================
-- 查看数据统计
-- ============================================
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;
SET FOREIGN_KEY_CHECKS = 1;