性能测试之如何构造海量数据

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

Jforum论坛部署完之后,用来做性能测试练习使用,接下来需要对它的主要业务进行熟悉,业务建模之前,对它的业务流程、数据库表结构也应当有所了解。

一、主流程

不论是公司的系统还是开源的项目,在做测试之前,都应该要熟悉它的主流程(主业务),才能更有利的设计测试用例。

  1. 用户注册
  2. 登录发帖
  3. 登录回帖
  4. 浏览
  5. 搜索
  6. 在页面能看到还有热门主题、最新主题等功能
1.1、独立场景

根据监控业务数据分析,假设发帖、回帖、浏览三个业务最为频繁,其中发帖和回帖都需要登录, 那么分别设立:登录、发帖、回帖、浏览四个独立业务场景;分别占比:30%、10%、15%、45%;其中发帖/回帖需要登录场景。

1.2、组合场景

用户登录之后分别发帖、回帖、浏览。

  1. 如何保证发帖、回帖的用户登录唯一?

  2. 如何设置脚本按业务不同比例分配执行?

1.3、关于脚本设计

是将多个场景使用一个线程组来控制呢,还是不同场景使用多个线程组来控制?

建议是多场景使用不同线程组来控制,而不建议所有业务场景使用一个线程组控制原因有二: 其一按业务占比不同业务场景并发用户数不一样,也不方便维护脚本; 其二线程组内的元件是顺序执行的,相互之间影响(参数),复杂度高。

而不同线程组之间,可以独立开,他们确是并行的,没有顺序可言,唯一的缺点是关于用户参数化,同1个用户不要出现在不同的场景里,按照系统鉴权方式,可能会出现第1个场景刚登录还没发帖,第二个场景就登录了,会导致第一个场景发帖失败,所以脚本组合如下:

  1. 登录+发帖

  2. 登录+回帖

  3. 只管浏览

二、性能指标

业务建模除了要理清楚流程之外,就需要对业务数据进行分析得到性能需求(指标);在不同的并发用户得到不同的RT、TPS等业务指标。

在前期是可以估算的,假设设置1个用户(线程),按业务比例执行业务场景,持续5分钟,得到一个基准值,或统计整个场景得到总TPS,再按比例分配;

如100线程并发,其中有30%的用户登录,10%去发帖,15%去回帖,45%浏览帖子,持续运行5分钟,假设总tps为55;预估各业务tps为:16.5、5.5、8.25、24.75;

实际按照上面的场景设计会发现只有25%的用户登录去发帖,那么30%的用户登录还有5%去浏览帖子了。比例为25%登录、10%发帖、15%回帖、50%浏览。

业务占比 登录25% 发帖10% 回帖15% 浏览50%
tps 13.75 5.5 8.25 27.5

三、数据构造

前面已知业务模型并估算性能指标,那么它一定不是发生在空服务器上,什么叫空服务器?我把业务数据量的多少来评估系统支撑的业务能力;

1000条数据和10万条数据所产生的压力肯定是不一样的,性能测试环境的部署应该还包括业务数据的准备。

3.1、数据来源

这时候需要做两件事,第一前面说过了,要熟悉业务流程,第二就对数据表结构有清晰的认识(业务意义)。

  1. Jforum_users、jforum_user_groups这两张表是对用户及用户用户权限有关

  2. jforum_forums、jforum_topics、jforum_posts、jforum_posts_text分别是论坛版块、主题、记录发帖回帖状态、记录发帖回帖内容

除此之外,其他数据表所覆盖的业务有限。

  • 注册用户
  • 发帖数据
  • 回帖数据
3.2、如何构造
  1. 一般思维,在不确定数据表业务含义的时候,保险的做法就是模拟客户端请求构造数据,参数化请求脚本;速度较慢且也容易错;

  2. 比较高效一点的呢,就是写存储过程,速度快;因为要多懂一点数据库知识,并且需要知道表业务结构,sql从哪里来?且往下看:

  3. 中庸的做法:先模拟客户端注册,然后观察得到后台的sql操作,然后提取出来,直接写成操作sql脚本;更简单;或写存储过程。

3.3、介绍mysql存储过程样例:
-- mysql默认结束符为;分号
delimiter $$  -- 自定义结束符
-- PROCEDURE 存储过程可以携带入参IN,out为出参,INOUT即为输入输出参数
CREATE PROCEDURE addUser(IN userid INTEGER,IN maxID INTEGER)
BEGIN
	DECLARE a VARCHAR(20);
	DECLARE m VARCHAR(20);
	DECLARE i int;
	SET i=userid +1;
	loop1: WHILE i<=maxID DO
		set a=CONCAT("test",i);
		set m=CONCAT(a,"@test.com");
		INSERT INTO jforum_users VALUES(i, 1, a,'70a9a7accbef6ceacae626cabe66723318be40cfc4d7abac0103340f0458230363677dd2ed96ae76f8a0493d27872eb093b55c1ddfcfb400bab9138cc42477', 0, 0, NULL, '2021-09-27 17:58:05', NULL, 88, '', NULL, '', '%d/%M/%Y %H:%i', 0, 0, NULL, NULL, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, NULL, 0,m, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
		insert into jforum_user_groups VALUES(1,i);
		SET i=i+1;
	END WHILE loop1;
END$$ -- 结束定义存储过程

delimiter ;  -- 最后记得还原,否则下面需要执行sql带分号就不认识了。

-- 通过参数调用,然存储过程变得活起来
set @userId=(select max(user_id) from jforum_users);
set @maxId=@userId+5;
call addUser(@userId,@maxId); -- 存储过程调用
复制代码

上面已经构造了用户数据,接下来就需要对发帖、回帖进行构造数据

delimiter $$
CREATE PROCEDURE addTopic()
BEGIN
	DECLARE topicId INT;
	DECLARE postId INT;
    DECLARE replayCount INT; -- 回复数
	DECLARE userId INT;
	DECLARE forumId INT;
	DECLARE createDate Datetime;
	DECLARE i int;
	SET i=1;
   SET replayCount=2; -- 因为构造了2条回复数据
	loop1: WHILE i<=100000 DO
           -- CEIL 返回最小整数
		set userId=2+CEIL(rand()*1002);
           -- 构造时间
		set createDate=DATE_ADD(now(),INTERVAL -3 DAY);
		set createDate=DATE_ADD(now(),INTERVAL -3 HOUR);
		set forumId=CEIL(rand()*4);
           -- 主题
		INSERT INTO jforum_topics VALUES(topicId, forumId, concat(i,"welcome to Jforum!!!"), userId, createDate, 1, replayCount, 0, 0, 0, i, i+2, 0, 0);
  
           -- 增加主题新增浏览数据
		INSERT INTO jforum_topics_watch VALUES (topicId, userId, 1);
		-- 帖子
		INSERT INTO jforum_posts  VALUES ((i-1)*3+1,topicId, forumId, userId, createDate, '192.168.2.188', 1, 0, 1, 0, NULL, 0, 1, 0, 0);
		INSERT INTO jforum_posts  VALUES ((i-1)*3+2,topicId, forumId, userId, createDate, '192.168.2.188', 1, 0, 1, 1, NULL, 0, 1, 0, 0);
		INSERT INTO jforum_posts  VALUES ((i-1)*3+3,topicId, forumId, userId, createDate, '192.168.2.188', 1, 0, 1, 1, NULL, 0, 1, 0, 0);
		-- 帖子内容
		INSERT INTO jforum_posts_text  VALUES ((i-1)*3+1, '[b][color=blue][size=18]Congratulations :!: [/size][/color][/b]\nYou have completed the installation, and JForum is up and running. \n\nTo start administering the board, login as [i]Admin / <the password you supplied in the installer>[/i] and access the [b][url=http://192.168.2.188:8080/jforum-2.7.0/admBase/login.page]Admin Control Panel[/url][/b] using the link that shows up in the bottom of the page. There you will be able to create Categories, Forums and much more  :D  \n\nFor more information and support, please refer to the following pages:\n\n:arrow: Community forum: http://jforum.andowson.com/\n:arrow: Documentation: https://sourceforge.net/p/jforum2/wiki2/Home\n\nThank you for choosing JForum.\n\nThe JForum Team\n\n', 'Welcome to JForum');
		INSERT INTO jforum_posts_text  VALUES ((i-1)*3+2, '一致好评', concat("回复","welcome to Jforum!!!"));
		INSERT INTO jforum_posts_text  VALUES ((i-1)*3+3, '好评如潮', concat("回复","welcome to Jforum!!!"));
		set i=i+1;
	END WHILE loop1;
END$$
delimiter ;
-- 调用存储过程
call addTopic();

-- 因为调试使用,需要有这个快速删除结构
TRUNCATE jforum_topics;
TRUNCATE jforum_posts;
TRUNCATE jforum_posts_text;
DROP PROCEDURE if EXISTS addTopic;

-- 数据构造完成,需要重启服务,会发现每个栏目下没有翻页数据,因为jforum_forums有两个字段:forum_topics总数forum_last_post_id最后一次回帖id
select count(topic_id),max(topic_id),forum_id from jforum_topics GROUP BY forum_id; 
-- 统计出来的数据替换jforum_forums表中的两个值forum_topics、forum_last_post_id;
select *from jforum_forums;
复制代码

这10万条数据,比调用脚本产生要快得多。6万条数据造了差不多大半天。

四、总结

准备性能测试数据的方案有多种,只看你熟悉哪种,最终都会提前准备好。

「欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边,抽奖详情见活动文章」。

猜你喜欢

转载自juejin.im/post/7016640656831414280