在LoadRunner中,事务是指用户在客户端做一种或多种业务所需要的操作集(actions),通过事务开始和结束函数可以标记完成该业务所需要的操作内容(脚本section);定义事务来衡量服务器的性能,例如,你可以定义一个事务来衡量服务器处理查看账户余额和显示信息于ATM的请求时间。
一个事务的时间是指持续时间,事务会完全记录下从事务开始到事务结束之间的时间差。对于一个事务时间来说,一般由4个部分组成:
事务响应时间=网络时间+服务器处理时间+网络延迟
事务的响应时间是通过记录用户请求的开始时间和服务器返回内容到客户端时间的差值来计算用户操作响应时间的。这里的响应时间不包含客户端GUI时间(如浏览器解释页面所消耗的时间),但是客户端导致的请求等待时间会被计算在内。
如下图所示:
对于软件来说,通过事务得到的系统响应时间也是由非常多的部分组成的,一般来说响应时间由网络时间、服务器处理时间、网络延迟三大部分组成。我们先看一下当一个客户端发出请求到服务器返回需要经历哪些路径,如下图2所示。
=》客户端发出请求首先通过网络来到Web Server;(消耗时间为N1)
=》然后Web Server将处理后的请求发送给App server;(消耗时间为N2)
=》App Server将操作数据指令发送给Database;(消耗时间为N3)
=》Database服务器将查询结果数据发送给App server;(消耗时间为N4)
=》App Server 将处理后的的页面发送给Web Server;(消耗时间为N5)
=》最后Web Server将HTML转发到客户端;(消耗时间为N6)
这里的Nx都是网络传输上时间的开销,没有计算业务处理所需要花费的时间
另外一个方面,还需要考虑各个服务器所需要的时间,Web Server处理时间WT、App Server处理时间AT、Database处理时间DT。
除了上面两种时间开销以外,还需要考虑网络延迟的问题。
所以最终的响应时间组成为:
响应时间=网络延迟时间+WT+AT+DT+(N1+N2+N3)+(N4+N5+N6)+ WT+AT+DT,
也可以简单认为响应时间是由网络开销(前端)+服务器开销(后端)两大部分组成,如下图3所示:
那么这些消耗时间都花在什么和事情上了呢?影响网络的因素一般包括以下内容:
DNS域名解析时间
事务中哪怕没有操作,也是需要时间的,不过这个时间一般是在0.01秒左右,所以可以忽略。
Action()
{ lr_start_transaction("test");
lr_end_transaction("test", LR_AUTO);
return 0;
}
运行脚本后,控制台输出如下:
Action.c(4): Notify: Transaction "test" started.
Action.c(6): Notify: Transaction "test" ended with "Pass" status (Duration: 0.0085).
Think Time是LoadRunner提供的一种模拟用户等待的方式,通过lr_think_time()函数实现。在函数内写入对应的时间(单位是秒),当脚本在Controller中运行到该函数时就会等待相应的时间。注意在VuGen中,回放Think Time默认关闭。
在Run-time Settings中设置Think Time,启用Replay Think Time功能,运行之后可以看到以下结果:
Action.c(4): Notify: Transaction "test" started.
Action.c(6): lr_think_time: 5.00 seconds.
Action.c(8): Notify: Transaction "test" ended with "Pass" status (Duration: 5.0224 Think Time: 4.9998).
所以Think Time会被算在事务的时间内,不过在Analysis中可以设置过滤规则将其扣除,另外我们建议尽量不要在事务内使用lr_think_time()函数。
在使用事务的时候,经常会看到在事务日志中有Wasted Time,Wasted Time是指事务中应该扣除的由于其他原因导致的时间浪费。如:执行一个计算密钥的程序,会浪费很多时间,这时候需要通过计算出wasted time来过滤事务时间,如下:
Action()
{ lr_start_transaction("首页");
web_url("index.php", "URL=http://www.51testing.com/index.php?action/category/catid/202/page/1/php/1/modified/1533787760000",
"Resource=0",
"RecContentType=text/html",
"Referer=http://www.51testing.com/html/02/category-catid-202.html",
"Snapshot=t3.inf",
"Mode=HTML",
LAST);
lr_end_transaction("首页", LR_AUTO);
return 0;
}
运行结果:
在默认情况下,LoadRunner会将自身脚本运行浪费的时间自动记录Wasted Time,例如执行关联,检查点等函数的时间。
除了脚本自身浪费的时间,某些时候使用C语言等外部接口进行处理所消耗的时间也会影响事务的时间,这个时间LoadRunner无法处理。这种情况lr无法处理,需要人为地计算第三方时间开销,并且将这个开销的时间记入Wasted Time中,例如:
Action()
{
int i;
int num=1000; //循环迭代次数
char dude[1000];
double time_elapsed; //处理循环的时间
double wasteTime; //浪费时间
double transaction_time; //事务自身时间
double totalWasteTime; //总的浪费时间
double test;
merc_timer_handle_t timer; //定时器
//开始事务
lr_start_transaction("Demo");
timer=lr_start_timer(); //开启计时器
for(i=0;i<=num;i++)
{
sprintf(dude,"This is the way we waste time in a script=%d",i);
}
//获取处理循环的时间(以秒为单位)
time_elapsed =lr_end_timer(timer);
//换算为毫秒
wasteTime= time_elapsed * 1000;
//获取事务自身时间,以毫秒为单位//注意,该语句必须放在事务中间,即事务结束之前
transaction_time = lr_get_transaction_wasted_time("Demo") * 1000;
//获取事务的持续时间并输出,以秒为单位
//test=lr_get_transaction_duration("Demo");
//lr_output_message("�", test);
lr_end_transaction("Demo", LR_AUTO);
totalWasteTime = transaction_time + wasteTime;
lr_wasted_time(totalWasteTime);
return 0;
}
其中lr_start_timer()是一个LoadRunner自带的时间计数器,它和lr_end_timer()相对应,能够返回这两个函数间的时间差。
为了确保响应时间的正确,需要扣除在运行脚本时自身的时间消耗,事务中尽量避免出现非请求的处理内容,如果无法避免请,使用lr_wasted_time()函数将多余的时间开销扣除。
注意:在计算Wasted Time时不要直接使用lr_wasted_time()覆盖,而忘了加上脚本中LoadRunner函数的自身时间。通过lr_get_transaction_wasted_time()函数可获得事务自身的Wasted Time,将这个时间累加上第三方统计的Wasted Time,再通过lr_wasted_time()函数覆盖。